/*!
 * \file reed_solomon.cc
 * \brief Class implementing a Reed-Solomon encoder/decoder for blocks of 255
 * symbols and symbols of 8 bits.
 * \author Carles Fernandez, 2021. cfernandez(at)cttc.es
 *
 * -----------------------------------------------------------------------------
 *
 * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
 * This file is part of GNSS-SDR.
 *
 * Copyright (C) 2010-2021  (see AUTHORS file for a list of contributors)
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * -----------------------------------------------------------------------------
 */

#include "reed_solomon.h"
#include <algorithm>
#include <cstring>
#include <iostream>


ReedSolomon::ReedSolomon(const std::string& gnss_signal)
{
    if (gnss_signal.empty() || gnss_signal == "E6B")
        {
            d_nroots = 223;    // number of parity symbols in a block
            d_min_poly = 29;   // minimal poly
            d_prim = 1;        // The primitive root of the generator poly.
            d_fcr = 1;         // first consecutive root of the Reed-Solomon generator polynomial
            d_pad = 0;         // the number of pad symbols in a block.
            d_shortening = 0;  // shortening parameter
            d_rows_G = 255;    // rows of generator matrix
            d_columns_G = 32;  // columns of generator matrix

            d_genmatrix = {
                {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                {19, 143, 180, 59, 221, 29, 49, 45, 231, 9, 73, 73, 159, 2, 158, 136, 212, 218, 14, 113, 215, 20, 187, 55, 137, 181, 203, 113, 97, 135, 14, 251},
                {27, 27, 1, 50, 255, 109, 251, 156, 148, 151, 85, 21, 74, 116, 250, 77, 60, 203, 113, 196, 213, 23, 202, 125, 31, 252, 90, 1, 176, 226, 44, 252},
                {98, 153, 190, 38, 223, 28, 28, 149, 170, 219, 41, 235, 236, 175, 113, 182, 239, 31, 74, 241, 127, 121, 207, 137, 205, 70, 88, 218, 250, 129, 99, 5},
                {95, 235, 199, 105, 168, 182, 233, 133, 201, 135, 171, 89, 50, 230, 115, 227, 21, 122, 41, 226, 93, 59, 20, 36, 30, 150, 134, 240, 34, 91, 183, 83},
                {172, 171, 163, 123, 27, 81, 14, 251, 24, 56, 15, 35, 244, 148, 24, 35, 96, 195, 47, 232, 148, 85, 117, 91, 39, 5, 74, 71, 104, 116, 14, 128},
                {117, 108, 167, 111, 201, 61, 244, 13, 5, 236, 75, 124, 11, 233, 60, 127, 101, 117, 144, 13, 51, 70, 138, 247, 188, 171, 120, 104, 141, 220, 39, 86},
                {243, 8, 122, 204, 147, 89, 112, 127, 204, 217, 20, 179, 8, 167, 203, 254, 95, 38, 22, 249, 215, 127, 101, 46, 99, 252, 183, 17, 8, 122, 191, 32},
                {90, 195, 11, 73, 110, 20, 55, 185, 206, 241, 12, 193, 185, 72, 141, 27, 97, 29, 251, 144, 6, 109, 129, 203, 222, 64, 164, 49, 173, 37, 167, 169},
                {164, 41, 177, 10, 34, 58, 123, 165, 122, 70, 108, 145, 240, 246, 208, 134, 248, 114, 237, 129, 149, 218, 70, 63, 105, 5, 184, 222, 9, 255, 213, 153},
                {211, 255, 215, 20, 146, 60, 12, 202, 1, 95, 234, 192, 175, 223, 81, 99, 59, 136, 191, 82, 138, 174, 112, 1, 21, 14, 137, 7, 4, 238, 50, 246},
                {220, 94, 230, 67, 248, 163, 186, 77, 68, 20, 1, 180, 150, 94, 127, 36, 154, 47, 101, 114, 172, 174, 172, 248, 130, 250, 55, 68, 17, 106, 3, 123},
                {110, 20, 220, 172, 53, 110, 224, 20, 10, 192, 59, 46, 159, 96, 14, 203, 214, 144, 215, 141, 13, 190, 175, 232, 55, 123, 104, 223, 79, 38, 146, 169},
                {164, 29, 102, 221, 199, 97, 1, 114, 215, 130, 93, 166, 31, 208, 248, 5, 40, 197, 96, 173, 136, 209, 149, 17, 74, 236, 131, 18, 231, 29, 214, 172},
                {251, 94, 49, 176, 56, 250, 251, 10, 237, 114, 111, 176, 78, 90, 148, 97, 69, 174, 3, 178, 4, 16, 151, 192, 36, 202, 212, 81, 210, 20, 219, 216},
                {116, 79, 18, 201, 172, 40, 33, 232, 54, 187, 32, 61, 5, 227, 55, 18, 43, 107, 202, 220, 141, 66, 224, 166, 158, 176, 61, 11, 143, 232, 112, 47},
                {187, 194, 174, 69, 228, 144, 68, 94, 189, 124, 254, 101, 65, 91, 176, 76, 117, 203, 236, 169, 202, 251, 11, 110, 242, 80, 181, 94, 162, 92, 111, 54},
                {29, 150, 209, 144, 66, 224, 111, 137, 81, 38, 230, 100, 15, 45, 7, 31, 208, 240, 210, 18, 111, 85, 199, 64, 247, 215, 164, 75, 231, 34, 69, 82},
                {191, 102, 106, 86, 63, 166, 105, 80, 243, 169, 231, 39, 86, 171, 77, 223, 72, 220, 171, 98, 179, 115, 160, 191, 202, 89, 192, 20, 178, 54, 121, 137},
                {254, 252, 23, 88, 159, 236, 167, 50, 34, 70, 225, 175, 28, 89, 25, 150, 163, 25, 241, 87, 152, 213, 166, 176, 237, 50, 249, 60, 144, 205, 27, 81},
                {138, 9, 193, 221, 141, 92, 54, 239, 124, 193, 92, 251, 33, 190, 134, 68, 160, 220, 80, 210, 146, 184, 240, 135, 188, 129, 101, 218, 102, 213, 132, 199},
                {184, 160, 40, 202, 31, 235, 178, 121, 225, 205, 231, 122, 61, 178, 191, 195, 55, 13, 2, 41, 245, 69, 128, 182, 5, 90, 7, 28, 79, 58, 11, 43},
                {247, 8, 171, 147, 180, 87, 67, 121, 151, 143, 177, 155, 64, 107, 163, 222, 211, 152, 178, 184, 68, 211, 218, 210, 252, 37, 84, 189, 44, 186, 133, 134},
                {31, 50, 155, 253, 213, 220, 84, 174, 239, 85, 87, 105, 214, 81, 160, 211, 90, 32, 239, 171, 171, 238, 177, 234, 36, 233, 216, 77, 44, 173, 205, 253},
                {113, 18, 35, 135, 205, 43, 156, 23, 127, 169, 162, 160, 15, 49, 202, 100, 165, 163, 175, 30, 199, 19, 141, 197, 211, 200, 134, 41, 215, 154, 34, 31},
                {204, 239, 127, 208, 89, 187, 30, 192, 37, 152, 221, 214, 211, 49, 93, 9, 93, 38, 25, 9, 6, 86, 219, 250, 25, 161, 185, 32, 98, 177, 32, 121},
                {72, 7, 24, 67, 1, 245, 154, 234, 84, 179, 37, 96, 222, 33, 64, 228, 78, 254, 194, 19, 197, 60, 60, 241, 58, 151, 184, 179, 233, 70, 85, 97},
                {253, 151, 182, 118, 101, 136, 118, 241, 195, 26, 152, 14, 225, 28, 193, 165, 140, 82, 138, 36, 216, 2, 152, 228, 117, 234, 180, 94, 11, 25, 50, 148},
                {20, 35, 254, 1, 198, 250, 222, 43, 98, 131, 180, 54, 101, 212, 227, 212, 85, 247, 217, 50, 117, 7, 116, 145, 101, 136, 176, 12, 83, 1, 146, 170},
                {145, 235, 144, 178, 16, 181, 198, 59, 220, 241, 197, 242, 187, 44, 243, 109, 86, 53, 21, 48, 83, 149, 252, 147, 181, 124, 48, 89, 151, 149, 227, 188},
                {214, 115, 72, 209, 6, 224, 24, 39, 114, 233, 248, 204, 31, 222, 125, 2, 236, 241, 19, 132, 104, 150, 172, 254, 222, 170, 104, 161, 199, 252, 179, 230},
                {241, 67, 229, 75, 108, 250, 81, 179, 127, 247, 83, 66, 159, 206, 107, 96, 58, 217, 252, 157, 139, 17, 235, 115, 5, 174, 191, 230, 233, 49, 241, 241},
                {165, 246, 113, 208, 142, 14, 235, 211, 178, 85, 75, 239, 238, 96, 147, 129, 143, 18, 30, 123, 124, 195, 21, 230, 104, 198, 220, 56, 202, 53, 246, 99},
                {219, 121, 50, 105, 81, 61, 239, 218, 41, 238, 236, 242, 77, 40, 161, 123, 92, 58, 122, 26, 3, 147, 12, 163, 109, 207, 110, 216, 66, 41, 93, 220},
                {56, 105, 223, 38, 38, 53, 34, 72, 93, 91, 133, 135, 1, 232, 7, 61, 70, 61, 102, 124, 94, 21, 181, 225, 227, 23, 51, 104, 159, 94, 117, 98},
                {200, 107, 25, 252, 122, 136, 229, 62, 85, 8, 171, 117, 186, 197, 183, 103, 52, 41, 91, 19, 211, 165, 97, 52, 227, 241, 116, 70, 115, 251, 56, 164},
                {99, 62, 142, 10, 191, 175, 135, 155, 202, 184, 151, 52, 17, 239, 5, 26, 201, 44, 159, 38, 76, 235, 82, 145, 61, 162, 223, 9, 169, 204, 77, 189},
                {197, 14, 41, 244, 99, 82, 51, 75, 53, 246, 248, 215, 70, 118, 32, 124, 79, 180, 4, 127, 169, 157, 105, 103, 85, 151, 125, 63, 246, 69, 228, 179},
                {55, 161, 79, 12, 207, 40, 253, 100, 230, 119, 111, 97, 76, 61, 94, 122, 5, 74, 200, 112, 206, 160, 19, 75, 142, 167, 222, 9, 180, 99, 57, 177},
                {17, 80, 149, 28, 144, 190, 229, 240, 26, 182, 124, 100, 217, 51, 52, 9, 182, 169, 42, 94, 114, 239, 69, 95, 173, 11, 101, 72, 64, 50, 3, 135},
                {12, 91, 119, 248, 135, 229, 140, 37, 129, 209, 39, 237, 182, 202, 102, 204, 89, 159, 208, 66, 154, 204, 54, 66, 32, 13, 61, 13, 184, 70, 75, 128},
                {117, 204, 87, 187, 74, 161, 64, 143, 219, 117, 162, 84, 197, 171, 98, 1, 138, 76, 204, 242, 153, 72, 19, 180, 165, 172, 112, 31, 199, 12, 21, 19},
                {24, 225, 130, 141, 144, 160, 197, 221, 109, 80, 74, 157, 237, 227, 1, 143, 161, 216, 190, 28, 103, 248, 231, 29, 74, 248, 192, 160, 226, 203, 254, 14},
                {242, 17, 183, 221, 223, 54, 147, 94, 222, 19, 137, 147, 116, 241, 4, 34, 163, 217, 140, 42, 34, 191, 244, 240, 48, 18, 110, 84, 212, 155, 159, 85},
                {198, 3, 198, 145, 91, 104, 40, 111, 171, 25, 48, 170, 91, 222, 108, 67, 99, 147, 168, 118, 148, 82, 76, 9, 226, 178, 78, 148, 151, 183, 234, 136},
                {237, 10, 198, 207, 133, 149, 88, 94, 250, 23, 24, 49, 14, 86, 242, 63, 235, 232, 176, 37, 91, 230, 60, 107, 210, 175, 217, 195, 113, 111, 148, 57},
                {252, 70, 251, 156, 71, 58, 104, 35, 181, 22, 29, 18, 45, 124, 115, 246, 91, 204, 171, 171, 10, 8, 109, 87, 86, 26, 6, 194, 111, 15, 44, 249},
                {61, 247, 189, 11, 255, 205, 190, 159, 73, 215, 216, 211, 50, 194, 165, 173, 247, 237, 123, 131, 188, 226, 189, 197, 112, 84, 126, 46, 193, 255, 184, 53},
                {40, 156, 37, 206, 118, 220, 97, 4, 164, 201, 150, 153, 5, 88, 33, 143, 80, 1, 230, 22, 33, 31, 14, 175, 218, 151, 224, 19, 52, 213, 244, 149},
                {7, 121, 65, 169, 163, 244, 187, 17, 112, 237, 46, 113, 109, 50, 57, 188, 171, 241, 132, 47, 144, 234, 210, 48, 167, 146, 6, 41, 127, 185, 80, 151},
                {33, 85, 209, 187, 99, 27, 241, 145, 182, 43, 152, 91, 166, 94, 114, 169, 45, 163, 104, 175, 26, 115, 76, 130, 55, 152, 136, 45, 135, 225, 32, 216},
                {116, 149, 25, 41, 167, 115, 192, 226, 173, 224, 121, 202, 238, 11, 51, 244, 227, 3, 199, 183, 144, 92, 131, 125, 220, 163, 111, 87, 243, 189, 133, 212},
                {160, 202, 250, 200, 192, 43, 249, 18, 14, 151, 249, 96, 181, 91, 160, 155, 39, 28, 47, 110, 5, 38, 203, 203, 1, 103, 73, 198, 63, 163, 145, 49},
                {100, 7, 242, 101, 230, 151, 67, 247, 146, 170, 239, 129, 240, 215, 250, 144, 17, 158, 47, 155, 183, 246, 28, 5, 202, 8, 216, 253, 69, 13, 144, 119},
                {186, 166, 166, 145, 230, 236, 133, 44, 96, 122, 206, 139, 96, 30, 65, 96, 251, 202, 46, 177, 105, 85, 144, 33, 232, 28, 135, 70, 64, 24, 189, 122},
                {125, 253, 144, 215, 58, 109, 158, 6, 140, 237, 28, 168, 63, 148, 208, 125, 70, 43, 60, 183, 25, 111, 239, 227, 103, 164, 69, 30, 44, 240, 238, 236},
                {79, 231, 215, 32, 107, 20, 43, 26, 230, 83, 183, 70, 84, 250, 132, 244, 30, 68, 74, 255, 253, 232, 200, 251, 43, 161, 44, 134, 187, 133, 145, 204},
                {21, 229, 206, 84, 62, 194, 60, 102, 75, 4, 220, 56, 176, 209, 192, 112, 8, 94, 248, 15, 74, 182, 177, 114, 195, 206, 113, 105, 159, 63, 57, 165},
                {112, 108, 180, 230, 202, 246, 252, 111, 117, 175, 210, 10, 195, 231, 143, 229, 10, 202, 230, 244, 135, 102, 250, 118, 242, 55, 43, 125, 231, 167, 135, 71},
                {205, 154, 65, 115, 150, 138, 189, 176, 159, 48, 250, 135, 228, 77, 78, 173, 208, 178, 71, 189, 8, 130, 129, 62, 19, 152, 204, 112, 34, 15, 42, 112},
                {195, 133, 16, 131, 217, 207, 15, 17, 168, 72, 182, 124, 156, 4, 38, 75, 208, 55, 40, 147, 80, 134, 226, 57, 75, 233, 92, 24, 247, 205, 149, 27},
                {128, 91, 2, 15, 14, 219, 62, 231, 152, 107, 5, 251, 73, 170, 42, 255, 5, 28, 181, 87, 240, 145, 152, 73, 251, 215, 147, 35, 202, 183, 79, 5},
                {95, 9, 5, 213, 129, 103, 46, 167, 187, 181, 27, 117, 34, 67, 118, 184, 92, 144, 42, 29, 251, 180, 252, 115, 222, 160, 23, 59, 219, 107, 129, 127},
                {34, 145, 97, 163, 240, 99, 224, 52, 91, 27, 163, 13, 24, 220, 81, 216, 61, 25, 80, 27, 25, 185, 99, 100, 162, 201, 57, 38, 169, 202, 171, 224},
                {155, 178, 152, 248, 234, 66, 116, 165, 4, 232, 10, 178, 59, 197, 10, 91, 34, 238, 48, 229, 220, 24, 121, 14, 142, 75, 92, 140, 53, 106, 227, 201},
                {74, 184, 197, 204, 104, 42, 159, 160, 168, 203, 23, 245, 157, 180, 35, 108, 4, 247, 100, 221, 252, 211, 44, 40, 161, 48, 91, 177, 109, 16, 224, 231},
                {226, 80, 154, 253, 172, 137, 170, 25, 31, 36, 56, 228, 57, 78, 159, 182, 128, 235, 244, 155, 5, 145, 21, 196, 90, 100, 238, 164, 152, 28, 19, 89},
                {18, 25, 164, 149, 142, 135, 198, 151, 60, 180, 76, 80, 230, 139, 21, 246, 110, 97, 210, 120, 168, 133, 5, 145, 244, 247, 37, 98, 209, 145, 37, 68},
                {248, 116, 245, 46, 159, 233, 159, 253, 83, 98, 58, 194, 2, 110, 157, 178, 162, 165, 254, 26, 224, 145, 178, 152, 114, 92, 76, 237, 158, 173, 14, 194},
                {231, 91, 11, 41, 98, 144, 242, 73, 175, 207, 52, 108, 221, 155, 179, 74, 98, 154, 77, 47, 145, 115, 196, 31, 141, 207, 26, 157, 128, 99, 69, 145},
                {75, 176, 108, 107, 23, 148, 51, 54, 134, 194, 17, 234, 222, 226, 184, 52, 25, 140, 39, 93, 210, 10, 104, 38, 9, 43, 85, 10, 104, 43, 222, 237},
                {92, 94, 46, 231, 10, 36, 227, 154, 49, 80, 209, 2, 137, 25, 108, 20, 131, 193, 227, 149, 192, 55, 22, 75, 103, 122, 104, 231, 206, 70, 68, 7},
                {121, 214, 117, 143, 206, 89, 179, 32, 21, 14, 178, 51, 248, 135, 228, 243, 2, 191, 235, 169, 138, 172, 49, 147, 211, 75, 49, 34, 221, 124, 108, 159},
                {185, 39, 183, 74, 227, 158, 201, 236, 236, 6, 9, 181, 104, 219, 67, 64, 140, 148, 86, 111, 106, 201, 187, 196, 168, 45, 71, 181, 163, 15, 149, 111},
                {15, 111, 192, 134, 62, 204, 46, 57, 198, 220, 244, 251, 221, 182, 220, 133, 4, 232, 180, 36, 154, 117, 97, 116, 109, 32, 152, 53, 121, 42, 47, 255},
                {87, 1, 11, 170, 17, 250, 238, 55, 59, 146, 185, 145, 190, 62, 12, 21, 70, 84, 123, 167, 251, 10, 125, 123, 66, 246, 196, 139, 109, 220, 185, 22},
                {71, 74, 17, 6, 15, 146, 107, 234, 137, 157, 221, 246, 241, 146, 72, 115, 22, 129, 144, 3, 158, 222, 200, 152, 18, 68, 90, 188, 142, 192, 24, 146},
                {126, 156, 188, 60, 66, 222, 98, 216, 17, 255, 152, 216, 248, 200, 14, 74, 65, 139, 46, 19, 154, 57, 21, 115, 8, 118, 158, 217, 234, 177, 111, 160},
                {47, 142, 147, 67, 44, 227, 21, 168, 151, 216, 89, 62, 250, 165, 74, 185, 147, 22, 5, 138, 55, 242, 24, 57, 100, 167, 83, 58, 175, 115, 63, 33},
                {73, 144, 57, 155, 60, 182, 188, 241, 254, 163, 68, 197, 171, 184, 17, 18, 242, 11, 197, 242, 162, 153, 183, 129, 64, 242, 52, 164, 231, 5, 160, 210},
                {202, 242, 96, 114, 134, 254, 154, 128, 117, 242, 17, 246, 223, 18, 112, 174, 3, 235, 3, 87, 136, 108, 179, 77, 236, 98, 152, 166, 151, 130, 13, 52},
                {59, 228, 148, 40, 210, 184, 99, 13, 92, 252, 250, 25, 191, 183, 111, 210, 135, 47, 238, 31, 34, 63, 59, 150, 219, 190, 29, 132, 221, 4, 135, 219},
                {65, 3, 105, 33, 78, 229, 48, 7, 5, 17, 117, 115, 16, 20, 101, 108, 249, 218, 89, 162, 68, 88, 31, 83, 78, 141, 9, 81, 249, 115, 114, 99},
                {219, 157, 199, 113, 160, 253, 4, 1, 253, 89, 168, 204, 209, 214, 213, 141, 177, 76, 178, 93, 218, 171, 151, 169, 216, 233, 37, 13, 43, 26, 27, 88},
                {1, 175, 221, 243, 223, 150, 131, 20, 195, 95, 120, 137, 81, 97, 19, 52, 129, 138, 123, 79, 185, 78, 132, 36, 16, 192, 99, 216, 25, 165, 45, 183},
                {123, 99, 4, 20, 155, 224, 253, 96, 2, 165, 255, 216, 84, 34, 11, 83, 58, 203, 206, 214, 133, 224, 22, 122, 211, 12, 130, 206, 202, 170, 225, 179},
                {55, 31, 34, 33, 47, 208, 79, 170, 205, 64, 60, 102, 67, 47, 10, 81, 42, 63, 183, 186, 103, 140, 110, 52, 147, 33, 69, 246, 69, 95, 214, 180},
                {78, 217, 117, 166, 51, 55, 232, 219, 136, 176, 59, 71, 7, 54, 250, 207, 62, 19, 105, 137, 20, 2, 4, 201, 69, 77, 35, 123, 71, 98, 9, 88},
                {1, 58, 153, 65, 8, 5, 73, 248, 25, 42, 145, 26, 218, 183, 243, 27, 195, 5, 36, 148, 109, 128, 45, 183, 112, 93, 199, 222, 111, 201, 85, 165},
                {112, 120, 107, 177, 223, 192, 59, 26, 235, 253, 252, 71, 225, 141, 233, 214, 97, 1, 189, 40, 28, 65, 204, 234, 55, 132, 184, 203, 80, 87, 113, 43},
                {247, 192, 115, 208, 207, 151, 104, 240, 244, 133, 129, 128, 125, 183, 156, 136, 198, 206, 190, 7, 69, 58, 222, 158, 160, 23, 138, 2, 251, 165, 232, 252},
                {98, 117, 101, 84, 61, 44, 230, 6, 198, 187, 59, 63, 121, 152, 178, 208, 42, 229, 79, 62, 188, 233, 226, 157, 46, 249, 179, 10, 249, 202, 36, 193},
                {210, 77, 203, 244, 98, 21, 100, 71, 96, 65, 54, 182, 156, 230, 250, 224, 97, 97, 31, 13, 209, 19, 108, 22, 14, 81, 255, 241, 196, 144, 48, 171},
                {130, 162, 74, 188, 56, 12, 24, 172, 87, 250, 78, 57, 164, 215, 95, 252, 182, 219, 141, 135, 187, 37, 83, 188, 187, 162, 34, 103, 11, 133, 124, 229},
                {196, 155, 245, 4, 123, 227, 238, 196, 192, 201, 155, 47, 214, 115, 221, 199, 165, 240, 196, 144, 236, 254, 136, 213, 193, 9, 247, 63, 140, 105, 154, 46},
                {168, 253, 206, 153, 244, 90, 190, 188, 118, 131, 197, 151, 204, 138, 190, 46, 116, 159, 121, 214, 81, 142, 12, 49, 8, 186, 199, 229, 247, 216, 224, 39},
                {35, 18, 213, 92, 18, 32, 163, 180, 130, 116, 180, 242, 103, 130, 93, 241, 167, 10, 104, 181, 54, 135, 118, 39, 89, 7, 169, 11, 99, 104, 47, 45},
                {157, 150, 134, 244, 214, 20, 46, 134, 50, 218, 163, 99, 173, 61, 240, 43, 35, 238, 145, 233, 16, 104, 165, 150, 124, 224, 137, 40, 96, 163, 243, 130},
                {83, 94, 239, 60, 225, 202, 211, 119, 171, 212, 59, 66, 104, 180, 180, 154, 216, 159, 161, 81, 129, 234, 220, 73, 126, 135, 22, 73, 32, 199, 236, 64},
                {180, 51, 88, 137, 101, 242, 22, 92, 8, 209, 99, 140, 86, 232, 224, 9, 185, 92, 56, 176, 178, 232, 11, 157, 180, 56, 55, 7, 44, 122, 96, 192},
                {193, 20, 57, 242, 98, 80, 139, 154, 221, 134, 21, 167, 176, 203, 20, 58, 108, 40, 168, 11, 136, 9, 214, 200, 135, 126, 245, 4, 168, 194, 142, 20},
                {97, 223, 113, 66, 240, 219, 163, 213, 247, 105, 91, 200, 228, 152, 156, 102, 140, 2, 240, 50, 129, 133, 160, 93, 174, 246, 89, 111, 195, 22, 26, 78},
                {70, 8, 143, 72, 73, 69, 52, 183, 169, 243, 7, 53, 53, 120, 43, 2, 105, 112, 241, 117, 239, 48, 104, 246, 141, 176, 208, 220, 126, 224, 229, 157},
                {159, 27, 28, 198, 131, 35, 183, 49, 168, 168, 102, 146, 77, 18, 157, 130, 200, 86, 133, 151, 5, 132, 76, 243, 194, 4, 55, 182, 159, 191, 21, 13},
                {199, 26, 140, 14, 238, 2, 67, 91, 6, 205, 170, 100, 199, 87, 74, 59, 207, 195, 16, 130, 205, 225, 88, 2, 88, 88, 210, 48, 97, 114, 249, 174},
                {221, 62, 67, 44, 76, 233, 250, 18, 23, 177, 178, 213, 175, 134, 50, 222, 206, 224, 25, 32, 152, 125, 204, 99, 56, 175, 235, 226, 50, 129, 168, 28},
                {249, 207, 146, 253, 136, 29, 143, 209, 20, 235, 30, 29, 26, 151, 85, 116, 134, 62, 72, 44, 92, 53, 101, 226, 57, 136, 158, 222, 10, 192, 41, 227},
                {174, 229, 7, 70, 206, 29, 89, 189, 213, 188, 33, 212, 151, 193, 254, 218, 239, 38, 5, 110, 143, 97, 37, 81, 142, 18, 93, 184, 110, 93, 251, 91},
                {52, 86, 100, 126, 146, 223, 48, 62, 75, 108, 70, 219, 245, 33, 187, 154, 183, 167, 3, 107, 238, 39, 158, 207, 110, 84, 216, 51, 15, 116, 120, 71},
                {205, 222, 123, 163, 14, 210, 148, 124, 206, 14, 57, 19, 53, 123, 136, 153, 175, 15, 42, 88, 151, 235, 192, 90, 170, 4, 175, 131, 108, 231, 249, 143},
                {148, 139, 48, 211, 158, 147, 117, 33, 102, 77, 237, 218, 77, 54, 170, 68, 39, 24, 6, 237, 106, 137, 131, 98, 25, 203, 36, 104, 92, 38, 238, 241},
                {165, 147, 185, 5, 22, 252, 130, 247, 32, 76, 241, 81, 118, 178, 107, 64, 171, 15, 223, 129, 12, 34, 141, 142, 121, 218, 185, 163, 68, 128, 225, 124},
                {23, 231, 58, 82, 90, 211, 40, 239, 63, 155, 129, 60, 128, 142, 31, 64, 164, 157, 221, 125, 225, 114, 37, 76, 217, 172, 3, 27, 146, 193, 82, 144},
                {88, 207, 100, 97, 177, 177, 65, 193, 199, 91, 12, 22, 17, 189, 51, 16, 199, 144, 46, 188, 87, 110, 210, 240, 211, 202, 253, 98, 143, 190, 114, 1},
                {19, 215, 123, 95, 188, 172, 128, 108, 38, 206, 18, 69, 137, 19, 35, 187, 196, 29, 158, 95, 107, 67, 213, 229, 121, 102, 1, 140, 3, 8, 176, 137},
                {254, 80, 166, 73, 150, 111, 173, 219, 30, 147, 134, 90, 126, 134, 161, 248, 199, 149, 48, 98, 165, 13, 150, 197, 183, 129, 198, 253, 8, 124, 37, 152},
                {192, 42, 26, 56, 12, 149, 104, 49, 152, 50, 118, 99, 251, 83, 191, 154, 145, 109, 86, 254, 190, 138, 28, 230, 102, 101, 198, 8, 70, 104, 191, 253},
                {113, 205, 59, 6, 8, 242, 213, 43, 224, 222, 197, 129, 5, 28, 200, 123, 236, 104, 226, 167, 146, 6, 233, 104, 223, 138, 10, 55, 146, 240, 231, 109},
                {41, 164, 95, 124, 213, 29, 32, 127, 210, 194, 190, 165, 202, 223, 58, 3, 138, 33, 84, 114, 225, 165, 197, 72, 206, 32, 180, 154, 57, 8, 204, 102},
                {132, 124, 62, 144, 115, 15, 9, 136, 217, 163, 11, 119, 222, 6, 194, 64, 125, 170, 127, 248, 166, 74, 7, 152, 84, 50, 72, 24, 24, 123, 86, 214},
                {134, 57, 102, 153, 222, 197, 231, 129, 183, 241, 40, 128, 43, 111, 140, 103, 38, 43, 154, 52, 249, 56, 182, 33, 235, 152, 83, 3, 178, 91, 75, 9},
                {139, 5, 68, 152, 226, 43, 97, 191, 13, 246, 202, 19, 147, 57, 117, 48, 93, 98, 85, 68, 21, 77, 50, 36, 148, 159, 69, 141, 77, 121, 37, 59},
                {218, 35, 129, 104, 183, 103, 180, 64, 135, 243, 110, 82, 44, 229, 61, 124, 225, 211, 61, 172, 216, 110, 173, 55, 22, 43, 189, 188, 227, 32, 38, 163},
                {26, 166, 237, 51, 2, 49, 255, 9, 59, 85, 142, 19, 204, 119, 216, 15, 196, 197, 79, 10, 236, 140, 159, 216, 166, 123, 78, 138, 105, 238, 188, 120},
                {91, 94, 229, 234, 63, 179, 33, 38, 122, 164, 161, 122, 132, 60, 152, 233, 156, 189, 47, 52, 17, 194, 93, 130, 145, 157, 169, 53, 34, 202, 4, 6},
                {106, 94, 193, 127, 30, 113, 21, 207, 78, 76, 15, 10, 31, 136, 95, 143, 43, 122, 153, 20, 252, 105, 127, 239, 147, 8, 29, 146, 110, 23, 238, 36},
                {22, 92, 183, 30, 142, 237, 219, 104, 197, 87, 160, 227, 70, 87, 224, 149, 103, 38, 159, 198, 144, 22, 65, 13, 1, 94, 91, 66, 183, 101, 242, 51},
                {66, 178, 17, 94, 151, 227, 231, 143, 59, 115, 189, 74, 80, 32, 215, 221, 170, 119, 9, 201, 172, 75, 71, 225, 3, 127, 106, 13, 3, 150, 74, 255},
                {87, 76, 214, 123, 201, 83, 193, 254, 141, 111, 22, 216, 15, 179, 154, 30, 30, 250, 228, 26, 22, 60, 67, 93, 215, 152, 155, 121, 85, 166, 5, 115},
                {246, 147, 7, 89, 171, 183, 133, 26, 210, 65, 50, 75, 127, 233, 103, 26, 2, 138, 114, 163, 147, 164, 140, 162, 174, 239, 28, 220, 93, 46, 46, 36},
                {22, 192, 122, 216, 168, 88, 29, 248, 16, 203, 173, 222, 7, 55, 129, 173, 242, 15, 111, 45, 39, 121, 140, 254, 76, 99, 188, 67, 249, 86, 203, 243},
                {131, 18, 135, 57, 186, 240, 43, 197, 42, 40, 229, 131, 81, 252, 75, 102, 247, 115, 212, 10, 127, 71, 22, 239, 234, 248, 154, 217, 173, 54, 141, 178},
                {36, 104, 231, 153, 223, 236, 110, 81, 143, 97, 248, 53, 135, 40, 74, 153, 203, 40, 1, 209, 108, 98, 114, 3, 143, 173, 122, 159, 51, 191, 68, 35},
                {111, 152, 170, 153, 65, 127, 209, 208, 212, 169, 111, 246, 131, 193, 189, 31, 103, 250, 231, 20, 74, 234, 76, 133, 117, 110, 181, 111, 128, 138, 112, 66},
                {146, 12, 235, 186, 103, 104, 193, 4, 124, 188, 140, 74, 193, 7, 180, 13, 137, 74, 65, 20, 68, 11, 96, 99, 119, 68, 85, 70, 200, 201, 49, 183},
                {123, 240, 167, 34, 210, 88, 3, 34, 18, 26, 28, 44, 151, 178, 109, 244, 3, 195, 14, 236, 222, 29, 83, 158, 148, 107, 6, 248, 84, 123, 141, 175},
                {206, 13, 29, 60, 189, 200, 145, 127, 137, 172, 44, 42, 120, 212, 73, 113, 213, 246, 23, 79, 33, 122, 139, 95, 45, 214, 19, 71, 155, 51, 175, 147},
                {109, 154, 79, 11, 165, 113, 9, 15, 99, 246, 224, 96, 187, 67, 214, 195, 151, 146, 87, 229, 1, 146, 10, 7, 70, 252, 199, 225, 112, 35, 146, 236},
                {79, 247, 176, 255, 183, 139, 55, 141, 239, 188, 172, 186, 156, 126, 83, 242, 160, 149, 243, 148, 175, 240, 53, 30, 207, 128, 116, 4, 68, 217, 66, 176},
                {2, 167, 119, 216, 190, 219, 119, 23, 20, 182, 254, 238, 157, 225, 233, 140, 234, 214, 251, 20, 65, 154, 174, 78, 113, 255, 137, 147, 44, 69, 183, 7},
                {121, 136, 140, 214, 241, 237, 76, 180, 152, 43, 84, 28, 20, 147, 28, 118, 154, 214, 252, 177, 11, 45, 156, 43, 214, 93, 180, 195, 169, 158, 111, 108},
                {58, 35, 174, 240, 216, 249, 14, 203, 170, 179, 2, 125, 200, 204, 43, 95, 83, 141, 228, 29, 32, 40, 85, 10, 4, 156, 168, 85, 172, 180, 172, 21},
                {114, 171, 242, 238, 47, 124, 59, 125, 65, 23, 39, 150, 161, 226, 5, 209, 61, 231, 91, 15, 64, 57, 58, 233, 229, 192, 112, 67, 243, 149, 98, 151},
                {33, 32, 3, 8, 36, 151, 121, 17, 218, 26, 98, 82, 65, 146, 162, 149, 64, 53, 126, 112, 58, 163, 159, 106, 238, 218, 218, 91, 237, 109, 12, 234},
                {37, 190, 149, 41, 64, 68, 119, 19, 153, 51, 235, 147, 203, 136, 225, 145, 52, 164, 112, 134, 242, 179, 185, 57, 179, 177, 210, 34, 165, 113, 40, 14},
                {242, 44, 232, 202, 123, 230, 119, 236, 16, 231, 234, 50, 122, 215, 111, 194, 189, 76, 240, 228, 184, 42, 191, 174, 20, 235, 39, 70, 86, 220, 37, 131},
                {64, 190, 225, 105, 2, 122, 16, 3, 38, 255, 79, 66, 166, 97, 192, 141, 229, 219, 13, 65, 91, 86, 37, 100, 207, 90, 214, 150, 47, 118, 157, 109},
                {41, 149, 44, 166, 186, 23, 168, 186, 250, 4, 159, 47, 9, 124, 71, 11, 124, 40, 231, 157, 7, 108, 149, 132, 194, 48, 100, 70, 152, 181, 74, 28},
                {249, 59, 57, 146, 2, 235, 113, 131, 188, 6, 171, 48, 224, 49, 175, 1, 83, 140, 128, 210, 225, 170, 116, 187, 222, 114, 1, 81, 174, 106, 29, 1},
                {19, 118, 143, 2, 79, 31, 218, 92, 100, 181, 79, 226, 175, 226, 175, 39, 213, 137, 130, 241, 5, 245, 17, 67, 50, 107, 185, 112, 48, 41, 100, 230},
                {241, 134, 224, 140, 191, 179, 174, 113, 4, 225, 15, 245, 177, 126, 87, 178, 31, 224, 132, 12, 254, 124, 136, 206, 184, 66, 126, 55, 56, 198, 36, 38},
                {48, 196, 26, 73, 218, 118, 123, 137, 168, 15, 159, 113, 154, 253, 55, 144, 239, 187, 25, 57, 59, 60, 63, 148, 47, 2, 154, 195, 208, 32, 63, 18},
                {11, 43, 62, 251, 191, 45, 35, 203, 140, 42, 121, 233, 87, 190, 201, 82, 228, 103, 71, 184, 123, 78, 40, 6, 227, 199, 165, 59, 95, 91, 220, 223},
                {13, 53, 76, 103, 206, 252, 97, 243, 120, 229, 154, 201, 166, 244, 46, 208, 14, 246, 41, 210, 152, 81, 184, 156, 192, 91, 123, 48, 223, 215, 21, 243},
                {131, 9, 114, 15, 5, 150, 143, 185, 33, 64, 203, 180, 70, 93, 136, 201, 138, 143, 45, 76, 128, 248, 62, 219, 136, 116, 162, 30, 222, 16, 12, 108},
                {58, 217, 47, 14, 1, 13, 117, 8, 167, 10, 105, 226, 96, 158, 229, 203, 236, 157, 189, 204, 221, 163, 128, 168, 244, 194, 129, 67, 113, 195, 34, 118},
                {169, 119, 204, 119, 80, 22, 46, 55, 120, 70, 39, 68, 156, 140, 150, 247, 116, 237, 35, 82, 233, 43, 126, 138, 204, 151, 134, 110, 159, 171, 125, 51},
                {66, 13, 58, 37, 254, 61, 28, 122, 100, 206, 172, 205, 247, 250, 12, 171, 200, 100, 194, 117, 56, 50, 122, 222, 132, 178, 163, 208, 47, 190, 132, 112},
                {195, 10, 135, 248, 143, 167, 184, 176, 98, 179, 72, 42, 214, 23, 145, 9, 214, 47, 254, 22, 152, 182, 82, 194, 171, 126, 118, 119, 87, 192, 36, 181},
                {93, 162, 212, 56, 55, 138, 174, 1, 117, 22, 129, 122, 212, 161, 92, 220, 178, 53, 119, 177, 111, 233, 133, 194, 58, 192, 183, 57, 167, 247, 152, 81},
                {138, 170, 159, 30, 237, 244, 80, 230, 79, 150, 12, 155, 244, 118, 126, 1, 234, 205, 124, 84, 116, 79, 204, 164, 206, 86, 151, 148, 99, 226, 190, 68},
                {248, 236, 70, 21, 20, 138, 236, 107, 34, 17, 24, 130, 201, 124, 96, 217, 85, 33, 82, 180, 204, 77, 120, 81, 71, 102, 237, 95, 104, 31, 125, 89},
                {18, 3, 24, 73, 102, 63, 197, 209, 78, 137, 121, 112, 128, 123, 39, 9, 1, 180, 24, 222, 135, 76, 217, 252, 97, 234, 39, 97, 42, 97, 38, 42},
                {228, 45, 188, 152, 234, 51, 166, 35, 216, 41, 188, 76, 213, 212, 244, 206, 205, 116, 5, 211, 100, 181, 104, 188, 63, 244, 47, 236, 48, 88, 208, 80},
                {153, 156, 164, 77, 144, 52, 216, 195, 138, 50, 122, 239, 93, 117, 149, 33, 44, 104, 51, 87, 193, 80, 43, 126, 57, 230, 104, 125, 215, 242, 31, 247},
                {207, 155, 49, 11, 124, 188, 131, 180, 170, 150, 37, 109, 38, 174, 75, 104, 12, 226, 139, 143, 126, 241, 233, 148, 116, 99, 20, 212, 10, 62, 17, 173},
                {232, 186, 3, 220, 51, 92, 23, 165, 204, 6, 50, 129, 26, 97, 116, 90, 252, 80, 42, 40, 241, 242, 12, 139, 40, 65, 144, 183, 117, 126, 246, 228},
                {215, 126, 89, 118, 198, 245, 143, 230, 46, 91, 46, 26, 241, 207, 245, 100, 215, 96, 65, 70, 148, 160, 228, 189, 127, 47, 223, 252, 61, 144, 111, 95},
                {120, 41, 21, 204, 241, 163, 28, 92, 171, 179, 152, 237, 125, 79, 247, 139, 126, 208, 125, 246, 189, 108, 137, 210, 156, 75, 238, 104, 210, 1, 141, 24},
                {181, 108, 111, 71, 59, 212, 1, 131, 225, 115, 37, 14, 100, 77, 222, 171, 164, 193, 64, 145, 241, 64, 162, 123, 150, 194, 113, 2, 25, 6, 145, 13},
                {199, 48, 251, 125, 111, 186, 180, 237, 180, 132, 113, 39, 91, 126, 21, 120, 230, 175, 135, 71, 203, 21, 156, 236, 208, 12, 20, 118, 213, 244, 64, 42},
                {228, 248, 143, 123, 222, 58, 35, 82, 228, 211, 177, 68, 130, 15, 241, 252, 188, 147, 30, 76, 253, 249, 49, 249, 47, 69, 201, 223, 39, 167, 69, 54},
                {29, 201, 235, 177, 124, 218, 197, 238, 93, 127, 73, 43, 46, 238, 83, 94, 96, 57, 138, 224, 138, 98, 197, 122, 96, 10, 177, 55, 102, 167, 190, 120},
                {91, 89, 138, 236, 189, 205, 202, 28, 157, 194, 139, 189, 188, 222, 1, 98, 205, 25, 211, 241, 251, 164, 179, 216, 51, 91, 216, 202, 159, 197, 77, 4},
                {76, 93, 179, 102, 191, 201, 9, 126, 167, 185, 251, 178, 251, 180, 156, 27, 21, 130, 33, 10, 138, 171, 114, 111, 198, 221, 80, 1, 83, 185, 253, 134},
                {31, 137, 206, 229, 32, 215, 202, 228, 232, 101, 97, 35, 255, 234, 127, 236, 159, 230, 245, 56, 25, 32, 201, 66, 153, 211, 32, 73, 144, 210, 206, 133},
                {42, 86, 219, 213, 217, 111, 135, 80, 70, 49, 102, 98, 210, 232, 158, 138, 9, 31, 131, 127, 79, 143, 146, 160, 50, 78, 110, 170, 123, 133, 183, 166},
                {69, 223, 198, 190, 49, 54, 2, 163, 119, 185, 60, 107, 37, 131, 9, 62, 145, 184, 181, 28, 147, 95, 19, 12, 166, 4, 235, 241, 135, 215, 47, 217},
                {103, 126, 39, 5, 127, 60, 220, 60, 120, 40, 162, 39, 65, 138, 112, 7, 160, 101, 210, 27, 244, 193, 20, 21, 219, 135, 56, 69, 78, 58, 189, 32},
                {90, 87, 125, 20, 167, 248, 82, 21, 141, 69, 253, 119, 45, 1, 160, 160, 152, 226, 184, 84, 228, 78, 63, 186, 229, 248, 223, 190, 249, 99, 231, 171},
                {130, 42, 80, 10, 216, 201, 245, 154, 5, 23, 74, 242, 101, 102, 184, 166, 246, 34, 14, 32, 226, 16, 14, 239, 23, 73, 139, 71, 68, 184, 143, 50},
                {81, 169, 211, 130, 94, 168, 242, 140, 46, 186, 180, 233, 222, 1, 120, 13, 77, 60, 3, 41, 157, 45, 250, 153, 104, 220, 182, 172, 103, 226, 153, 121},
                {72, 154, 94, 239, 83, 242, 137, 6, 24, 184, 7, 9, 225, 44, 112, 193, 74, 238, 216, 9, 229, 167, 71, 208, 89, 230, 197, 188, 101, 67, 6, 216},
                {116, 252, 214, 166, 243, 67, 41, 154, 58, 78, 234, 85, 188, 76, 65, 246, 139, 100, 138, 7, 54, 163, 87, 118, 142, 205, 17, 26, 98, 95, 39, 242},
                {144, 255, 15, 174, 25, 182, 1, 220, 175, 11, 41, 141, 69, 69, 174, 46, 120, 208, 177, 158, 130, 66, 119, 3, 235, 143, 255, 5, 149, 42, 138, 165},
                {112, 233, 174, 39, 48, 209, 136, 82, 207, 75, 221, 255, 118, 18, 27, 139, 84, 186, 104, 189, 22, 174, 14, 176, 131, 31, 106, 243, 139, 173, 146, 244},
                {250, 254, 133, 76, 108, 59, 53, 147, 15, 200, 135, 17, 138, 131, 147, 99, 199, 233, 75, 71, 240, 26, 199, 232, 60, 27, 173, 69, 39, 246, 92, 48},
                {119, 210, 114, 33, 191, 38, 98, 22, 244, 162, 249, 182, 30, 234, 188, 43, 61, 164, 212, 142, 73, 23, 155, 62, 96, 128, 111, 104, 167, 146, 203, 65},
                {167, 152, 96, 47, 165, 177, 203, 192, 142, 135, 92, 7, 61, 156, 32, 137, 220, 99, 13, 180, 186, 52, 77, 237, 74, 147, 251, 15, 108, 122, 59, 28},
                {249, 181, 52, 222, 139, 244, 215, 224, 198, 114, 40, 243, 200, 5, 79, 102, 209, 44, 203, 56, 200, 23, 44, 99, 183, 250, 162, 206, 231, 158, 210, 112},
                {195, 177, 63, 246, 116, 210, 113, 123, 248, 17, 244, 174, 232, 40, 110, 74, 27, 54, 182, 31, 213, 70, 119, 148, 22, 77, 62, 118, 73, 8, 4, 227},
                {174, 223, 121, 235, 197, 225, 150, 67, 127, 80, 219, 62, 36, 51, 65, 225, 209, 187, 13, 144, 188, 232, 86, 67, 248, 61, 152, 24, 198, 30, 51, 118},
                {169, 227, 202, 33, 181, 210, 194, 212, 51, 158, 125, 246, 64, 200, 59, 83, 94, 208, 5, 226, 181, 74, 53, 92, 39, 155, 121, 119, 196, 28, 160, 34},
                {124, 154, 149, 143, 36, 8, 222, 81, 182, 28, 217, 58, 223, 4, 195, 230, 121, 181, 17, 97, 174, 39, 223, 245, 163, 115, 72, 29, 9, 250, 221, 93},
                {94, 129, 132, 118, 175, 123, 131, 87, 207, 57, 77, 136, 126, 101, 29, 176, 73, 215, 180, 68, 41, 126, 101, 135, 219, 224, 57, 29, 241, 38, 251, 65},
                {167, 177, 51, 217, 242, 161, 150, 33, 207, 188, 199, 179, 3, 252, 175, 40, 71, 23, 126, 212, 112, 84, 36, 19, 243, 40, 155, 89, 25, 44, 143, 44},
                {142, 157, 145, 41, 142, 233, 158, 158, 64, 158, 34, 89, 115, 91, 16, 81, 46, 212, 130, 142, 166, 58, 205, 243, 193, 255, 109, 107, 83, 94, 185, 217},
                {103, 181, 101, 82, 232, 131, 3, 160, 69, 31, 133, 57, 115, 220, 168, 30, 207, 218, 190, 44, 102, 244, 113, 203, 36, 224, 195, 195, 212, 238, 52, 182},
                {104, 138, 170, 151, 231, 202, 217, 205, 81, 42, 246, 108, 123, 2, 40, 96, 196, 95, 144, 98, 49, 43, 23, 184, 181, 141, 105, 31, 176, 224, 164, 81},
                {138, 159, 183, 96, 66, 36, 16, 145, 131, 178, 48, 236, 226, 217, 221, 117, 86, 187, 22, 179, 167, 17, 14, 54, 180, 217, 218, 74, 69, 245, 169, 120},
                {91, 206, 220, 176, 108, 243, 52, 201, 226, 28, 70, 196, 123, 18, 54, 236, 230, 47, 81, 109, 168, 137, 192, 19, 127, 143, 11, 161, 226, 230, 31, 19},
                {24, 207, 128, 6, 155, 134, 151, 169, 43, 105, 35, 121, 125, 93, 184, 219, 76, 180, 221, 129, 248, 201, 38, 206, 237, 34, 227, 219, 92, 238, 20, 4},
                {76, 30, 37, 108, 85, 239, 66, 35, 18, 15, 80, 26, 63, 117, 31, 162, 172, 3, 140, 4, 250, 168, 31, 250, 208, 3, 41, 58, 66, 122, 214, 223},
                {13, 114, 121, 124, 89, 22, 163, 146, 144, 123, 191, 224, 85, 156, 229, 6, 254, 190, 77, 25, 36, 208, 94, 171, 60, 104, 191, 188, 222, 202, 52, 249},
                {61, 6, 137, 137, 31, 211, 146, 84, 248, 242, 181, 113, 192, 186, 69, 59, 7, 72, 9, 101, 14, 204, 101, 246, 140, 62, 12, 151, 191, 78, 125, 45},
                {157, 136, 146, 168, 3, 25, 221, 183, 210, 160, 37, 98, 46, 154, 200, 51, 233, 78, 211, 136, 192, 80, 238, 133, 173, 53, 176, 141, 252, 127, 213, 208},
                {236, 37, 13, 175, 18, 251, 87, 187, 224, 204, 128, 5, 91, 147, 115, 122, 151, 89, 90, 163, 65, 38, 17, 122, 231, 248, 212, 192, 124, 138, 107, 170},
                {145, 19, 150, 65, 190, 97, 199, 178, 76, 115, 138, 198, 136, 18, 180, 253, 248, 247, 187, 179, 194, 161, 221, 246, 94, 254, 64, 61, 91, 186, 104, 69},
                {235, 120, 75, 39, 150, 196, 72, 209, 145, 27, 180, 77, 11, 2, 154, 155, 125, 233, 102, 2, 252, 239, 45, 119, 156, 67, 142, 249, 160, 160, 43, 116},
                {143, 165, 24, 101, 222, 187, 133, 80, 114, 98, 164, 11, 16, 227, 43, 133, 145, 213, 75, 107, 148, 34, 89, 73, 28, 136, 140, 131, 231, 105, 2, 209},
                {255, 184, 148, 30, 2, 59, 196, 206, 224, 101, 11, 205, 173, 175, 148, 17, 245, 251, 207, 74, 117, 102, 216, 250, 162, 252, 162, 141, 19, 22, 115, 134},
                {31, 58, 43, 194, 88, 106, 56, 41, 88, 34, 189, 211, 128, 188, 100, 228, 149, 6, 140, 214, 89, 223, 4, 232, 12, 183, 1, 187, 28, 146, 97, 11},
                {173, 159, 50, 163, 30, 151, 172, 58, 118, 11, 139, 20, 227, 150, 135, 213, 107, 120, 100, 176, 68, 197, 190, 248, 82, 15, 225, 61, 55, 196, 240, 250},
                {8, 42, 165, 143, 186, 179, 64, 44, 100, 15, 30, 158, 136, 10, 240, 220, 181, 174, 221, 223, 195, 144, 160, 79, 89, 146, 43, 90, 157, 51, 97, 249},
                {61, 3, 209, 85, 236, 48, 55, 183, 70, 6, 193, 208, 190, 103, 211, 46, 221, 3, 25, 245, 200, 43, 37, 8, 104, 91, 246, 3, 89, 13, 132, 120},
                {91, 121, 64, 214, 89, 93, 32, 238, 196, 217, 242, 53, 71, 78, 136, 226, 189, 164, 233, 98, 238, 230, 250, 56, 65, 83, 137, 141, 171, 250, 231, 62},
                {133, 122, 163, 187, 119, 181, 55, 152, 138, 23, 49, 26, 211, 59, 150, 19, 144, 166, 205, 184, 82, 209, 107, 20, 157, 165, 177, 216, 27, 103, 147, 81},
                {138, 114, 71, 105, 110, 180, 111, 127, 214, 105, 13, 43, 148, 113, 228, 203, 37, 239, 239, 238, 125, 114, 244, 74, 24, 241, 242, 146, 130, 94, 46, 79},
                {85, 108, 150, 69, 191, 198, 106, 86, 228, 219, 78, 42, 73, 10, 92, 242, 16, 3, 18, 27, 228, 216, 36, 149, 19, 179, 28, 6, 226, 38, 163, 82},
                {191, 46, 144, 17, 234, 91, 79, 85, 44, 28, 26, 143, 24, 237, 106, 132, 165, 28, 88, 162, 186, 248, 45, 92, 31, 189, 164, 172, 255, 51, 125, 111},
                {15, 105, 201, 161, 101, 197, 235, 191, 127, 28, 238, 232, 231, 198, 234, 172, 192, 193, 60, 42, 87, 165, 80, 226, 245, 151, 8, 214, 96, 118, 19, 23},
                {84, 157, 205, 255, 217, 251, 101, 194, 230, 208, 26, 232, 23, 201, 46, 29, 123, 221, 11, 53, 196, 102, 220, 130, 2, 70, 240, 1, 178, 74, 188, 195},
                {244, 120, 86, 42, 110, 203, 209, 158, 119, 115, 207, 5, 104, 140, 138, 113, 25, 153, 59, 171, 105, 67, 136, 70, 30, 10, 203, 80, 13, 200, 172, 216},
                {116, 64, 52, 174, 54, 126, 16, 194, 162, 33, 33, 157, 176, 197, 225, 12, 59, 55, 253, 228, 148, 47, 179, 185, 24, 138, 253, 20, 142, 55, 172, 88}};

            d_genpoly_coeff = {88, 216, 195, 23, 111, 82, 79, 81, 62, 120, 249,
                250, 11, 134, 209, 116, 69, 170, 208, 45, 249, 223, 4, 19, 120,
                81, 182, 217, 44, 65, 93, 34, 118, 227, 112, 28, 65, 48, 244,
                165, 242, 216, 121, 50, 171, 32, 217, 166, 133, 134, 4, 120, 54,
                42, 13, 24, 95, 228, 173, 247, 80, 42, 89, 68, 81, 181, 112, 51,
                118, 108, 243, 223, 18, 38, 230, 1, 28, 109, 131, 14, 234, 151,
                21, 108, 7, 176, 236, 147, 175, 183, 66, 35, 178, 243, 36, 115,
                255, 51, 36, 6, 120, 163, 59, 9, 214, 102, 109, 253, 152, 137,
                1, 144, 124, 241, 143, 71, 91, 227, 28, 174, 13, 157, 78, 20,
                192, 64, 130, 45, 39, 46, 229, 171, 193, 252, 43, 165, 88, 180,
                179, 183, 88, 99, 219, 52, 210, 33, 160, 146, 22, 255, 111, 159,
                7, 237, 145, 194, 68, 89, 231, 201, 224, 127, 5, 27, 112, 71,
                165, 204, 236, 122, 119, 49, 212, 216, 151, 149, 53, 249, 57,
                136, 85, 14, 19, 128, 135, 177, 179, 189, 164, 98, 220, 99, 241,
                230, 188, 170, 148, 97, 121, 31, 253, 134, 43, 199, 81, 137, 82,
                54, 47, 216, 172, 169, 123, 246, 153, 169, 32, 86, 128, 83, 5,
                252, 251, 1};
        }
    else if (gnss_signal == "E1B")
        {
            d_nroots = 60;
            d_min_poly = 29;
            d_prim = 1;
            d_fcr = 195;
            d_pad = 0;
            d_shortening = 137;
            d_rows_G = 118;
            d_columns_G = 58;

            d_genmatrix = {
                {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                {193, 146, 156, 183, 62, 35, 90, 25, 89, 208, 43, 148, 117, 199, 92, 112, 4, 70, 74, 183, 37, 100, 118, 44, 238, 107, 186, 200, 179, 63, 140, 194, 176, 131, 38, 110, 33, 178, 43, 173, 98, 96, 105, 115, 90, 76, 133, 194, 133, 182, 99, 20, 183, 90, 84, 131, 26, 139},
                {91, 221, 65, 59, 102, 79, 66, 118, 29, 43, 164, 253, 13, 228, 108, 106, 252, 230, 45, 237, 12, 149, 152, 235, 143, 178, 102, 199, 227, 65, 230, 178, 140, 133, 93, 213, 89, 41, 198, 197, 215, 94, 122, 58, 18, 251, 179, 187, 61, 1, 239, 229, 179, 214, 244, 97, 202, 42},
                {190, 173, 125, 234, 225, 164, 122, 176, 130, 152, 32, 205, 41, 44, 78, 230, 128, 101, 92, 134, 176, 227, 128, 184, 180, 130, 142, 165, 134, 141, 110, 153, 50, 65, 25, 14, 98, 172, 34, 94, 181, 210, 38, 49, 15, 55, 169, 204, 233, 34, 197, 138, 78, 134, 181, 57, 82, 206},
                {154, 48, 226, 109, 5, 179, 159, 79, 237, 32, 199, 98, 33, 127, 219, 8, 110, 36, 68, 76, 24, 100, 105, 49, 245, 131, 53, 59, 61, 75, 216, 146, 103, 132, 185, 132, 24, 216, 243, 97, 70, 233, 161, 6, 10, 226, 77, 85, 182, 219, 24, 87, 154, 117, 124, 3, 106, 233},
                {101, 12, 238, 213, 120, 140, 44, 51, 196, 68, 201, 121, 36, 108, 200, 161, 56, 97, 123, 115, 237, 146, 54, 164, 141, 59, 232, 60, 60, 36, 85, 169, 129, 61, 49, 75, 21, 19, 49, 124, 195, 252, 63, 207, 153, 125, 144, 60, 39, 141, 117, 232, 96, 5, 162, 38, 187, 80},
                {58, 136, 130, 2, 173, 144, 135, 249, 194, 161, 38, 205, 85, 247, 142, 247, 228, 245, 99, 151, 114, 158, 68, 235, 185, 203, 78, 14, 149, 18, 163, 149, 250, 51, 198, 100, 15, 234, 113, 242, 230, 245, 22, 250, 196, 114, 38, 80, 103, 157, 65, 57, 4, 107, 109, 16, 9, 131},
                {231, 109, 52, 176, 87, 22, 48, 253, 54, 106, 47, 175, 119, 108, 137, 133, 99, 143, 63, 81, 242, 135, 75, 49, 22, 130, 125, 185, 168, 229, 196, 43, 92, 226, 57, 76, 149, 140, 100, 86, 217, 135, 132, 114, 90, 208, 180, 174, 150, 112, 147, 191, 11, 164, 32, 117, 5, 36},
                {197, 18, 114, 255, 50, 100, 185, 124, 218, 88, 190, 215, 41, 191, 206, 138, 120, 5, 243, 244, 111, 223, 137, 234, 221, 169, 43, 39, 143, 82, 41, 137, 149, 2, 84, 3, 143, 219, 88, 107, 118, 9, 200, 15, 221, 43, 131, 249, 253, 37, 40, 189, 116, 164, 225, 126, 177, 188},
                {152, 246, 146, 92, 78, 104, 171, 40, 30, 39, 246, 202, 204, 246, 55, 63, 240, 204, 63, 221, 233, 17, 105, 240, 166, 128, 153, 215, 115, 174, 39, 28, 112, 195, 178, 227, 100, 75, 117, 74, 82, 114, 105, 148, 192, 160, 58, 182, 232, 67, 140, 167, 147, 187, 216, 183, 66, 19},
                {88, 233, 3, 20, 252, 51, 135, 113, 130, 146, 84, 13, 81, 30, 147, 99, 56, 10, 63, 185, 42, 166, 207, 88, 220, 165, 199, 7, 86, 27, 71, 58, 216, 213, 113, 126, 19, 45, 56, 108, 143, 26, 252, 120, 123, 185, 143, 39, 153, 166, 78, 151, 33, 124, 208, 125, 40, 233},
                {73, 120, 195, 119, 81, 197, 85, 70, 175, 109, 204, 25, 136, 117, 21, 195, 222, 74, 162, 75, 237, 9, 155, 148, 242, 157, 99, 129, 206, 123, 255, 182, 75, 94, 57, 229, 151, 178, 115, 53, 34, 17, 139, 20, 30, 190, 82, 126, 204, 133, 128, 61, 227, 71, 16, 86, 4, 201},
                {62, 195, 117, 83, 179, 169, 59, 213, 201, 116, 240, 164, 198, 84, 105, 89, 127, 51, 126, 50, 81, 215, 167, 203, 139, 96, 251, 23, 173, 37, 188, 176, 235, 36, 53, 56, 67, 148, 47, 18, 237, 164, 221, 182, 234, 200, 51, 29, 243, 115, 114, 246, 173, 29, 62, 127, 167, 14},
                {169, 67, 240, 110, 142, 45, 20, 35, 20, 206, 92, 117, 106, 151, 17, 35, 2, 94, 255, 101, 84, 49, 101, 168, 17, 122, 73, 59, 87, 175, 103, 105, 140, 56, 62, 64, 5, 220, 188, 80, 138, 214, 246, 235, 11, 222, 227, 230, 54, 55, 52, 88, 237, 16, 238, 237, 27, 194},
                {88, 216, 182, 118, 206, 243, 194, 206, 137, 152, 189, 167, 238, 184, 242, 69, 36, 248, 173, 121, 146, 27, 239, 84, 132, 18, 61, 215, 186, 63, 70, 122, 173, 41, 138, 242, 176, 76, 175, 165, 149, 194, 88, 231, 4, 114, 241, 254, 201, 120, 58, 47, 222, 2, 123, 75, 114, 176},
                {188, 19, 183, 35, 242, 4, 50, 148, 5, 83, 98, 226, 132, 70, 109, 207, 93, 173, 89, 56, 167, 215, 50, 7, 10, 227, 169, 183, 90, 56, 48, 240, 253, 128, 253, 243, 52, 59, 182, 102, 244, 200, 169, 111, 38, 177, 75, 71, 199, 90, 47, 66, 186, 31, 231, 86, 23, 111},
                {23, 55, 128, 7, 36, 174, 140, 216, 161, 135, 112, 142, 248, 244, 169, 173, 126, 229, 219, 233, 3, 40, 112, 29, 130, 246, 246, 170, 182, 54, 85, 154, 76, 227, 6, 219, 121, 94, 24, 81, 142, 202, 226, 212, 231, 55, 200, 225, 62, 28, 217, 96, 242, 50, 143, 249, 1, 118},
                {36, 111, 216, 59, 50, 180, 160, 75, 113, 134, 211, 91, 182, 143, 169, 101, 207, 67, 126, 96, 42, 56, 183, 225, 15, 184, 125, 128, 115, 21, 76, 214, 228, 55, 135, 200, 122, 54, 10, 195, 57, 215, 193, 137, 218, 47, 31, 75, 201, 19, 226, 46, 219, 252, 171, 244, 153, 190},
                {202, 21, 206, 182, 17, 61, 151, 229, 64, 62, 73, 178, 215, 44, 252, 93, 5, 209, 253, 16, 63, 35, 156, 48, 132, 142, 110, 111, 142, 65, 41, 174, 240, 80, 64, 126, 247, 108, 249, 9, 154, 80, 102, 29, 170, 52, 203, 253, 175, 191, 82, 31, 64, 248, 79, 31, 153, 237},
                {63, 144, 241, 65, 93, 237, 185, 69, 251, 58, 85, 58, 152, 193, 129, 101, 152, 224, 102, 114, 197, 80, 147, 168, 161, 35, 37, 176, 37, 19, 150, 140, 126, 239, 31, 84, 110, 203, 7, 62, 79, 48, 27, 101, 153, 52, 2, 110, 203, 86, 143, 164, 144, 196, 194, 80, 87, 17},
                {20, 217, 37, 96, 55, 13, 235, 165, 222, 135, 30, 148, 34, 171, 224, 35, 95, 56, 14, 247, 5, 181, 213, 16, 162, 2, 124, 197, 27, 211, 78, 31, 186, 240, 5, 6, 25, 69, 239, 23, 105, 5, 142, 36, 99, 80, 157, 139, 199, 218, 129, 93, 53, 150, 145, 76, 209, 173},
                {102, 239, 33, 51, 4, 178, 28, 177, 128, 137, 105, 141, 208, 44, 210, 248, 152, 72, 255, 24, 26, 112, 197, 180, 35, 51, 35, 150, 104, 152, 253, 28, 134, 112, 41, 200, 80, 83, 171, 151, 10, 167, 71, 162, 53, 204, 242, 207, 41, 54, 32, 236, 75, 36, 132, 91, 34, 112},
                {230, 225, 186, 12, 73, 187, 104, 52, 239, 137, 241, 251, 194, 35, 227, 12, 21, 251, 1, 210, 178, 186, 187, 212, 199, 45, 72, 126, 86, 110, 94, 159, 88, 238, 94, 182, 143, 236, 43, 42, 34, 71, 81, 29, 120, 105, 177, 144, 178, 120, 255, 94, 193, 145, 44, 236, 247, 141},
                {131, 247, 106, 160, 99, 127, 254, 236, 225, 79, 24, 221, 242, 124, 91, 71, 209, 121, 237, 27, 217, 152, 35, 103, 27, 7, 61, 28, 185, 73, 182, 77, 200, 106, 117, 51, 96, 56, 125, 37, 61, 213, 103, 101, 88, 83, 102, 162, 159, 216, 31, 113, 68, 132, 78, 30, 248, 98},
                {141, 134, 43, 202, 72, 109, 204, 33, 132, 193, 51, 182, 43, 212, 100, 221, 126, 205, 46, 77, 190, 130, 181, 189, 175, 208, 165, 139, 133, 24, 113, 224, 15, 96, 20, 206, 175, 176, 68, 217, 213, 95, 140, 58, 214, 164, 80, 48, 161, 118, 97, 194, 209, 247, 238, 230, 26, 34},
                {214, 148, 137, 44, 243, 55, 191, 63, 77, 214, 201, 75, 217, 156, 103, 212, 104, 128, 241, 41, 83, 85, 83, 182, 214, 56, 127, 110, 57, 214, 249, 25, 236, 146, 192, 92, 101, 119, 184, 14, 83, 139, 28, 130, 232, 139, 88, 56, 204, 204, 150, 58, 197, 3, 51, 115, 171, 240},
                {45, 176, 137, 213, 83, 71, 180, 128, 251, 170, 151, 33, 125, 122, 145, 152, 32, 29, 244, 173, 19, 175, 36, 161, 46, 108, 88, 154, 198, 123, 60, 147, 246, 64, 239, 179, 146, 240, 54, 156, 124, 91, 75, 164, 1, 18, 169, 50, 26, 173, 131, 149, 102, 70, 251, 159, 11, 242},
                {101, 187, 110, 190, 192, 218, 216, 24, 11, 82, 67, 41, 103, 48, 205, 235, 168, 47, 66, 195, 12, 153, 253, 233, 29, 224, 7, 81, 157, 223, 101, 77, 128, 172, 245, 29, 34, 153, 25, 185, 62, 198, 141, 37, 59, 118, 96, 216, 64, 33, 3, 115, 162, 249, 145, 161, 39, 49},
                {94, 206, 2, 170, 252, 165, 52, 243, 243, 102, 47, 226, 182, 51, 212, 93, 231, 98, 241, 134, 172, 160, 3, 137, 198, 160, 51, 66, 153, 220, 86, 62, 128, 24, 198, 71, 126, 233, 228, 243, 31, 158, 125, 24, 203, 239, 228, 59, 74, 135, 132, 63, 183, 76, 5, 9, 143, 167},
                {62, 212, 195, 146, 110, 4, 91, 180, 124, 40, 251, 71, 61, 106, 47, 152, 225, 10, 86, 97, 156, 150, 14, 83, 150, 84, 198, 71, 110, 114, 27, 25, 99, 239, 115, 199, 225, 125, 116, 133, 43, 153, 82, 64, 230, 29, 98, 171, 182, 245, 112, 242, 175, 73, 53, 106, 248, 133},
                {65, 208, 229, 79, 178, 119, 149, 48, 150, 242, 149, 110, 57, 7, 128, 153, 202, 211, 206, 218, 3, 45, 91, 82, 253, 98, 180, 185, 153, 212, 22, 233, 116, 66, 62, 79, 247, 165, 192, 32, 79, 200, 68, 87, 209, 89, 71, 144, 241, 160, 165, 119, 126, 62, 7, 20, 178, 125},
                {66, 194, 199, 72, 30, 167, 104, 8, 188, 230, 72, 45, 18, 64, 35, 84, 64, 224, 143, 99, 244, 77, 194, 171, 115, 86, 200, 40, 205, 185, 128, 199, 14, 197, 255, 61, 184, 242, 31, 99, 85, 216, 129, 3, 72, 182, 211, 150, 26, 45, 164, 63, 218, 97, 181, 182, 26, 172},
                {46, 73, 249, 186, 70, 166, 170, 161, 98, 165, 160, 141, 25, 242, 131, 190, 43, 45, 12, 242, 21, 247, 30, 156, 188, 150, 124, 206, 42, 21, 99, 201, 162, 50, 212, 179, 52, 108, 180, 204, 174, 41, 140, 123, 14, 106, 68, 154, 100, 177, 54, 58, 66, 215, 92, 137, 24, 216},
                {131, 63, 194, 227, 213, 112, 227, 46, 116, 194, 52, 140, 132, 167, 138, 39, 99, 71, 59, 22, 249, 63, 110, 194, 83, 124, 134, 40, 9, 53, 205, 112, 158, 144, 169, 185, 101, 131, 253, 186, 219, 89, 9, 184, 62, 37, 101, 87, 149, 14, 214, 184, 32, 7, 8, 110, 157, 141},
                {42, 239, 135, 195, 81, 125, 136, 127, 58, 211, 123, 157, 75, 107, 154, 100, 161, 46, 157, 58, 123, 179, 20, 189, 215, 98, 69, 18, 175, 20, 175, 11, 27, 127, 17, 177, 82, 77, 58, 140, 53, 23, 43, 11, 64, 33, 1, 163, 115, 59, 46, 114, 185, 216, 43, 233, 30, 109},
                {187, 107, 37, 79, 138, 135, 199, 125, 100, 160, 209, 101, 79, 175, 142, 182, 14, 16, 33, 85, 179, 136, 192, 221, 110, 59, 128, 190, 176, 114, 107, 181, 8, 123, 87, 3, 82, 100, 79, 166, 32, 172, 206, 166, 177, 16, 30, 27, 156, 47, 3, 241, 186, 3, 233, 75, 189, 170},
                {9, 165, 153, 194, 5, 174, 10, 63, 16, 164, 181, 18, 107, 155, 255, 189, 32, 70, 255, 198, 172, 116, 102, 163, 87, 238, 208, 19, 207, 81, 226, 130, 36, 223, 98, 234, 108, 136, 113, 176, 188, 113, 103, 29, 43, 131, 26, 247, 17, 208, 158, 247, 22, 55, 98, 62, 83, 91},
                {122, 218, 243, 230, 181, 240, 78, 230, 125, 90, 141, 63, 181, 72, 34, 163, 211, 215, 3, 128, 106, 59, 113, 131, 158, 208, 182, 227, 2, 45, 162, 58, 49, 199, 209, 30, 40, 232, 161, 64, 126, 69, 193, 153, 253, 55, 57, 194, 77, 251, 139, 85, 136, 246, 82, 129, 112, 108},
                {3, 23, 252, 210, 151, 185, 126, 184, 72, 131, 93, 160, 61, 246, 134, 64, 40, 203, 79, 34, 204, 149, 25, 221, 12, 193, 154, 85, 73, 152, 29, 129, 176, 161, 171, 238, 217, 105, 239, 86, 255, 10, 209, 131, 23, 37, 231, 26, 18, 135, 175, 22, 116, 6, 51, 194, 87, 235},
                {19, 239, 7, 48, 105, 219, 196, 193, 243, 116, 95, 221, 73, 66, 231, 53, 8, 176, 139, 131, 2, 10, 74, 187, 90, 36, 199, 11, 209, 224, 181, 56, 51, 115, 183, 217, 134, 79, 181, 170, 252, 113, 6, 84, 254, 59, 138, 194, 181, 204, 63, 218, 218, 9, 135, 240, 75, 4},
                {118, 105, 33, 252, 158, 172, 57, 215, 1, 102, 65, 97, 114, 123, 228, 46, 77, 159, 175, 112, 2, 78, 135, 37, 128, 188, 73, 95, 136, 97, 211, 225, 153, 170, 208, 55, 32, 27, 122, 127, 162, 200, 171, 237, 182, 165, 230, 222, 31, 80, 218, 186, 33, 56, 95, 30, 193, 34},
                {6, 172, 37, 99, 30, 134, 173, 200, 150, 224, 104, 27, 101, 244, 250, 32, 37, 125, 178, 237, 232, 225, 10, 194, 38, 62, 40, 146, 22, 161, 1, 149, 232, 164, 114, 174, 164, 162, 21, 137, 28, 74, 253, 47, 236, 27, 24, 160, 99, 150, 248, 253, 248, 32, 175, 98, 175, 234},
                {154, 136, 227, 53, 140, 76, 189, 152, 149, 52, 191, 42, 247, 51, 3, 188, 168, 129, 92, 162, 115, 60, 107, 187, 143, 17, 137, 157, 10, 219, 244, 253, 107, 94, 92, 239, 184, 30, 253, 86, 145, 64, 57, 221, 20, 1, 97, 228, 218, 81, 172, 106, 237, 195, 218, 25, 49, 20},
                {14, 142, 223, 89, 178, 180, 186, 230, 37, 21, 217, 61, 213, 111, 83, 33, 88, 216, 192, 230, 12, 2, 136, 41, 188, 132, 163, 107, 195, 180, 59, 177, 232, 241, 187, 138, 165, 223, 243, 87, 177, 4, 57, 80, 43, 195, 13, 36, 232, 89, 143, 255, 208, 27, 118, 64, 9, 126},
                {193, 156, 18, 104, 103, 145, 238, 163, 191, 245, 62, 77, 72, 18, 51, 35, 37, 30, 146, 119, 195, 104, 116, 164, 199, 215, 62, 107, 216, 252, 56, 249, 1, 107, 215, 213, 171, 23, 244, 94, 53, 209, 109, 74, 10, 103, 70, 207, 161, 94, 58, 155, 72, 138, 79, 245, 90, 130},
                {79, 59, 250, 36, 207, 70, 246, 222, 60, 177, 165, 41, 204, 234, 152, 167, 149, 103, 155, 164, 187, 3, 17, 106, 13, 56, 133, 163, 235, 220, 120, 143, 129, 186, 95, 61, 175, 136, 71, 10, 115, 67, 117, 1, 45, 98, 49, 241, 153, 52, 208, 110, 173, 47, 113, 244, 61, 144},
                {251, 48, 41, 161, 98, 4, 23, 58, 118, 137, 248, 53, 112, 216, 84, 215, 230, 30, 47, 192, 128, 172, 163, 224, 153, 32, 247, 171, 185, 250, 215, 122, 108, 176, 103, 100, 88, 226, 193, 41, 242, 37, 192, 195, 80, 138, 188, 51, 47, 149, 155, 136, 53, 252, 19, 64, 193, 142},
                {124, 242, 42, 20, 52, 143, 229, 10, 57, 221, 174, 40, 150, 213, 224, 204, 178, 33, 118, 18, 244, 244, 237, 3, 222, 160, 236, 31, 243, 114, 105, 73, 192, 178, 102, 101, 53, 94, 197, 3, 132, 227, 160, 186, 34, 225, 141, 34, 52, 76, 102, 119, 181, 212, 14, 205, 191, 213},
                {18, 64, 11, 249, 128, 124, 136, 8, 208, 164, 247, 53, 52, 35, 117, 134, 253, 34, 226, 165, 253, 103, 53, 43, 10, 195, 107, 215, 253, 44, 79, 166, 118, 115, 128, 1, 187, 156, 116, 38, 55, 38, 104, 27, 189, 70, 245, 66, 54, 172, 51, 147, 164, 178, 22, 189, 253, 110},
                {186, 131, 99, 220, 159, 82, 188, 47, 130, 235, 80, 242, 18, 26, 119, 140, 149, 68, 174, 53, 227, 91, 10, 152, 118, 211, 236, 58, 19, 86, 67, 191, 40, 102, 127, 135, 84, 178, 104, 78, 20, 130, 120, 219, 219, 165, 194, 5, 198, 44, 83, 108, 68, 100, 192, 6, 80, 203},
                {244, 1, 47, 157, 50, 104, 143, 121, 171, 22, 185, 89, 161, 84, 117, 207, 80, 102, 206, 80, 112, 208, 81, 221, 226, 101, 99, 138, 24, 202, 173, 238, 196, 243, 122, 135, 30, 65, 224, 10, 207, 251, 255, 153, 6, 227, 204, 111, 108, 15, 154, 216, 146, 153, 174, 27, 154, 46},
                {166, 77, 140, 145, 232, 144, 89, 158, 148, 141, 37, 165, 157, 162, 192, 200, 9, 9, 104, 112, 87, 52, 200, 120, 142, 45, 51, 235, 242, 210, 120, 215, 74, 253, 40, 204, 70, 217, 114, 147, 235, 77, 87, 158, 168, 173, 127, 182, 243, 109, 81, 99, 102, 163, 156, 151, 214, 50},
                {235, 88, 105, 58, 29, 99, 50, 220, 211, 227, 31, 24, 23, 181, 195, 94, 74, 2, 153, 222, 56, 121, 105, 55, 131, 212, 174, 111, 223, 208, 196, 124, 12, 40, 90, 94, 6, 220, 75, 174, 126, 71, 86, 38, 60, 251, 12, 123, 23, 235, 46, 225, 213, 196, 219, 254, 253, 173},
                {167, 130, 60, 200, 96, 187, 40, 113, 160, 84, 38, 24, 41, 222, 144, 171, 225, 27, 143, 56, 22, 41, 127, 36, 234, 121, 79, 140, 113, 99, 114, 84, 85, 69, 215, 249, 41, 254, 25, 158, 209, 208, 108, 9, 109, 223, 220, 156, 92, 80, 114, 87, 64, 158, 130, 146, 138, 215},
                {108, 47, 174, 236, 151, 205, 169, 124, 151, 201, 168, 91, 80, 176, 57, 217, 13, 166, 171, 95, 96, 91, 149, 209, 18, 164, 249, 213, 250, 137, 237, 234, 214, 216, 233, 152, 7, 248, 2, 105, 38, 58, 205, 209, 27, 40, 167, 68, 228, 43, 79, 118, 135, 82, 40, 15, 50, 86},
                {41, 109, 177, 142, 47, 51, 187, 195, 198, 206, 119, 44, 158, 252, 67, 181, 212, 88, 228, 139, 126, 213, 82, 234, 75, 124, 215, 142, 248, 125, 35, 8, 11, 167, 53, 206, 180, 110, 70, 132, 89, 158, 220, 141, 167, 220, 220, 66, 176, 128, 95, 118, 86, 241, 187, 89, 169, 89},
                {19, 197, 125, 125, 53, 99, 78, 4, 136, 250, 18, 247, 197, 225, 237, 240, 253, 76, 24, 40, 171, 184, 10, 240, 109, 99, 122, 70, 10, 81, 80, 6, 186, 200, 177, 71, 166, 34, 178, 3, 46, 215, 146, 89, 240, 139, 115, 249, 237, 110, 56, 42, 186, 43, 112, 120, 208, 250},
                {76, 132, 133, 106, 171, 24, 138, 136, 53, 120, 173, 40, 116, 36, 165, 27, 205, 167, 81, 15, 168, 148, 227, 184, 214, 205, 123, 4, 108, 148, 229, 196, 244, 145, 144, 100, 250, 196, 117, 187, 145, 44, 231, 188, 176, 64, 13, 231, 127, 178, 180, 241, 61, 83, 21, 91, 102, 129},
                {48, 210, 222, 175, 41, 107, 16, 81, 186, 110, 8, 71, 8, 48, 88, 203, 67, 80, 210, 123, 187, 227, 142, 241, 160, 79, 25, 237, 118, 57, 179, 239, 140, 1, 31, 71, 136, 158, 180, 190, 132, 130, 153, 179, 180, 177, 193, 7, 102, 67, 155, 145, 219, 53, 159, 224, 186, 35},
                {42, 92, 106, 223, 29, 129, 147, 140, 69, 29, 215, 161, 128, 231, 13, 182, 77, 14, 138, 211, 22, 241, 200, 93, 228, 145, 118, 141, 106, 107, 163, 117, 132, 109, 128, 7, 172, 160, 39, 197, 49, 72, 240, 155, 75, 171, 149, 7, 35, 200, 99, 63, 144, 35, 25, 126, 144, 74},
                {208, 233, 31, 47, 4, 122, 82, 145, 161, 246, 27, 245, 202, 177, 213, 121, 8, 131, 31, 207, 85, 30, 100, 142, 53, 205, 170, 102, 118, 16, 234, 141, 112, 36, 21, 182, 63, 246, 166, 158, 44, 135, 62, 122, 72, 187, 234, 187, 70, 199, 128, 31, 122, 67, 112, 185, 130, 81}};

            d_genpoly_coeff = {1, 208, 42, 48, 76, 19, 41, 108, 167, 235, 166, 244, 186, 18, 124, 251, 79, 193, 14, 154, 6, 118, 19, 3, 122, 9, 187, 42, 131, 46, 66, 65, 62, 94, 101, 45, 214, 141, 131, 230, 102, 20, 63, 202, 36, 23, 188, 88, 169, 62, 73, 88, 152, 197, 231, 58, 101, 154, 190, 91, 193};
        }
    else
        {
            std::cerr << "Unknown Reead Solomon configuration. Setting basic defaults for Galileo E6B.\n";
            // Set E6B parameters by default
            d_nroots = 223;    // number of parity symbols in a block
            d_min_poly = 29;   // minimal poly
            d_prim = 1;        // The primitive root of the generator poly.
            d_fcr = 1;         // first consecutive root of the Reed-Solomon generator polynomial
            d_pad = 0;         // the number of pad symbols in a block.
            d_shortening = 0;  // shortening parameter
            d_rows_G = 0;
            d_columns_G = 0;
            d_genpoly_coeff = {88, 216, 195, 23, 111, 82, 79, 81, 62, 120, 249,
                250, 11, 134, 209, 116, 69, 170, 208, 45, 249, 223, 4, 19, 120,
                81, 182, 217, 44, 65, 93, 34, 118, 227, 112, 28, 65, 48, 244,
                165, 242, 216, 121, 50, 171, 32, 217, 166, 133, 134, 4, 120, 54,
                42, 13, 24, 95, 228, 173, 247, 80, 42, 89, 68, 81, 181, 112, 51,
                118, 108, 243, 223, 18, 38, 230, 1, 28, 109, 131, 14, 234, 151,
                21, 108, 7, 176, 236, 147, 175, 183, 66, 35, 178, 243, 36, 115,
                255, 51, 36, 6, 120, 163, 59, 9, 214, 102, 109, 253, 152, 137,
                1, 144, 124, 241, 143, 71, 91, 227, 28, 174, 13, 157, 78, 20,
                192, 64, 130, 45, 39, 46, 229, 171, 193, 252, 43, 165, 88, 180,
                179, 183, 88, 99, 219, 52, 210, 33, 160, 146, 22, 255, 111, 159,
                7, 237, 145, 194, 68, 89, 231, 201, 224, 127, 5, 27, 112, 71,
                165, 204, 236, 122, 119, 49, 212, 216, 151, 149, 53, 249, 57,
                136, 85, 14, 19, 128, 135, 177, 179, 189, 164, 98, 220, 99, 241,
                230, 188, 170, 148, 97, 121, 31, 253, 134, 43, 199, 81, 137, 82,
                54, 47, 216, 172, 169, 123, 246, 153, 169, 32, 86, 128, 83, 5,
                252, 251, 1};
        }

    d_data_in_block = d_symbols_per_block - d_nroots;
    d_info_symbols_shortened = d_data_in_block - d_shortening;
    d_data_symbols_shortened = d_symbols_per_block - d_shortening;

    d_a0 = static_cast<uint8_t>(d_symbols_per_block);
    d_genpoly_index = std::vector<uint8_t>(d_nroots + 1);

    init_log_tables();
    init_alpha_tables();
}


ReedSolomon::ReedSolomon(int nroots,
    int minpoly,
    int prim,
    int fcr,
    int pad,
    int shortening,
    const std::vector<uint8_t>& genpoly_coeff,
    const std::vector<std::vector<uint8_t>>& gen_matrix)
{
    if (fcr < 0 || fcr >= (1 << d_symsize))
        {
            std::cerr << "Reed Solomon wrong configuration: fcr must be 0 < frc <= 255\n";
            return;
        }
    if (prim <= 0 || prim >= (1 << d_symsize))
        {
            std::cerr << "Reed Solomon wrong configuration: prim must be 0 <= prim <= 255\n";
            return;
        }
    if (nroots < 0 || nroots >= (1 << d_symsize))
        {
            // Can't have more roots than symbol values!
            std::cerr << "Reed Solomon wrong configuration: nroots must be 0 < nroots <= 255\n";
            return;
        }
    if (pad < 0 || pad >= ((1 << d_symsize) - 1 - nroots))
        {
            // Too much padding
            std::cerr << "Reed Solomon wrong configuration: pad must be 0 < pad <= 255-nroots\n";
            return;
        }

    if (shortening < 0 || shortening >= (d_symbols_per_block - nroots))
        {
            // Too much shortening
            std::cerr << "Reed Solomon wrong configuration: shortening must be 0 < shortening <= 255-nroots\n";
            return;
        }

    d_nroots = nroots;
    d_data_in_block = d_symbols_per_block - d_nroots;
    d_min_poly = minpoly;
    d_prim = prim;
    d_pad = pad;
    d_a0 = static_cast<uint8_t>(d_symbols_per_block);
    d_fcr = fcr;
    d_shortening = shortening;
    d_info_symbols_shortened = d_data_in_block - d_shortening;
    d_data_symbols_shortened = d_symbols_per_block - d_shortening;

    if (!genpoly_coeff.empty() && (int(genpoly_coeff.size()) == d_nroots + 1))
        {
            d_genpoly_coeff = genpoly_coeff;
        }
    else
        {
            if (!genpoly_coeff.empty())
                {
                    std::cerr << "Reed Solomon wrong configuration: genpoly_coeff should be of size "
                              << d_nroots + 1 << ", but it of size " << genpoly_coeff.size() << '\n';
                }
            d_genpoly_coeff = std::vector<uint8_t>(nroots + 1, 0);
        }

    size_t rows_G = gen_matrix.size();
    if (rows_G != 0)
        {
            size_t columns_G = gen_matrix[0].size();
            if ((rows_G != d_data_symbols_shortened) || (columns_G != d_info_symbols_shortened))
                {
                    std::cerr << "Reed Solomon wrong configuration: gen_matrix should be of size ("
                              << d_data_symbols_shortened << "x" << d_info_symbols_shortened << ")"
                              << ", but it is (" << rows_G << "x" << columns_G << ")" << '\n';
                }
            else
                {
                    d_rows_G = rows_G;
                    d_columns_G = columns_G;
                    d_genmatrix = gen_matrix;
                }
        }

    d_genpoly_index = std::vector<uint8_t>(d_nroots + 1);

    init_log_tables();
    init_alpha_tables();
}


int ReedSolomon::mod255(int x) const
{
    while (x >= d_symbols_per_block)
        {
            x -= d_symbols_per_block;
            x = (x >> d_symsize) + (x & d_symbols_per_block);
        }
    return x;
}


int ReedSolomon::rs_min(int a, int b) const
{
    return (a) < (b) ? (a) : (b);
}


uint8_t ReedSolomon::galois_mul(uint8_t a, uint8_t b) const
{
    uint8_t p = 0;
    uint8_t carry;
    int i;
    for (i = 0; i < d_symsize; i++)
        {
            if (b & 1)
                {
                    p ^= a;
                }
            carry = a & 0x80;
            a = a << 1;
            if (carry)
                {
                    a ^= d_min_poly;
                }
            b = b >> 1;
        }
    return p;
}


uint8_t ReedSolomon::galois_add(uint8_t a, uint8_t b) const
{
    return a ^ b;
}


uint8_t ReedSolomon::galois_mul_table(uint8_t a, uint8_t b) const
{
    if (a == 0 || b == 0)
        {
            return 0;
        }

    uint8_t x = d_log_table[a];
    uint8_t y = d_log_table[b];
    uint8_t log_mult = (x + y) % d_symbols_per_block;

    return d_antilog[log_mult];
}


void ReedSolomon::init_log_tables()
{
    d_log_table[0] = 0;  // dummy value
    for (int i = 0, x = 1; i < d_symbols_per_block; x = galois_mul(x, d_min_poly), i++)
        {
            d_log_table[x] = i;
            d_antilog[i] = x;
        }
}


void ReedSolomon::init_alpha_tables()
{
    // Generate Galois field lookup tables
    d_index_of[0] = d_a0;
    d_alpha_to[d_a0] = 0;
    int sr = 1;
    for (int i = 0; i < d_symbols_per_block; i++)
        {
            d_index_of[sr] = i;
            d_alpha_to[i] = sr;
            sr <<= 1;
            if (sr & (1 << d_symsize))
                {
                    sr ^= d_min_poly;
                }
            sr &= d_symbols_per_block;
        }

    if (sr != 1)
        {
            std::cerr << "Reed Solomon wrong configuration: Field generator polynomial is not primitive!\n";
            return;
        }

    // Find prim-th root of 1, used in decoding
    int iprim;
    for (iprim = 1; (iprim % d_prim) != 0; iprim += d_symbols_per_block)
        {
        };
    d_iprim = iprim / d_prim;

    // get indexes of generator polymonial coefficients
    for (int i = 0; i <= d_nroots; i++)
        {
            d_genpoly_index[i] = d_index_of[d_genpoly_coeff[i]];
        }
}


std::vector<uint8_t> ReedSolomon::encode_with_generator_matrix(const std::vector<uint8_t>& data_to_encode) const
{
    std::vector<uint8_t> encoded_output(d_data_symbols_shortened, 0);
    if (d_rows_G == 0)
        {
            std::cerr << "Reed Solomon usage problem: Generator matrix is not defined.\n";
            return encoded_output;
        }
    if (data_to_encode.size() != d_columns_G)
        {
            std::cerr << "Reed Solomon usage problem: wrong vector input size in encode_with_generator_matrix method.\n";
            return encoded_output;
        }

    // Matrix-vector product in the Galoise field
    for (size_t i = 0; i < d_rows_G; i++)
        {
            for (size_t k = 0; k < d_columns_G; k++)
                {
                    encoded_output[i] = galois_add(encoded_output[i], galois_mul_table(d_genmatrix[i][k], data_to_encode[k]));
                }
        }
    return encoded_output;
}


std::vector<uint8_t> ReedSolomon::encode_with_generator_poly(const std::vector<uint8_t>& data_to_encode) const
{
    std::vector<uint8_t> encoded_output(d_data_symbols_shortened, 0);

    if (data_to_encode.size() != d_info_symbols_shortened)
        {
            std::cerr << "Reed Solomon usage problem: wrong vector input size in encode_with_generator_poly method.\n";
            return encoded_output;
        }

    std::copy(data_to_encode.begin(), data_to_encode.end(), encoded_output.begin());

    if (d_shortening == 0)
        {
            encode_rs_8(encoded_output.data(), encoded_output.data() + d_data_in_block);
        }
    else
        {
            std::vector<uint8_t> unshortened_encoded_output(d_symbols_per_block, 0);
            std::copy(data_to_encode.begin(), data_to_encode.end(), unshortened_encoded_output.begin());
            encode_rs_8(unshortened_encoded_output.data(), unshortened_encoded_output.data() + d_data_in_block);
            std::copy(unshortened_encoded_output.begin() + d_data_in_block, unshortened_encoded_output.end(), encoded_output.begin() + d_info_symbols_shortened);
        }
    return encoded_output;
}


void ReedSolomon::encode_rs_8(const uint8_t* data, uint8_t* parity) const
{
    int i;
    int j;
    uint8_t feedback;

    for (i = 0; i < d_symbols_per_block - d_nroots - d_pad; i++)
        {
            feedback = d_index_of[data[i] ^ parity[0]];
            if (feedback != d_a0)
                {
                    // feedback term is non-zero
                    feedback = mod255(d_symbols_per_block - d_genpoly_index[d_nroots] + feedback);
                    for (j = 1; j < d_nroots; j++)
                        {
                            parity[j] ^= d_alpha_to[mod255(feedback + d_genpoly_index[d_nroots - j])];
                        }
                }
            // Shift
            memmove(&parity[0], &parity[1], sizeof(uint8_t) * (d_nroots - 1));
            if (feedback != d_a0)
                {
                    parity[d_nroots - 1] = d_alpha_to[mod255(feedback + d_genpoly_index[0])];
                }
            else
                {
                    parity[d_nroots - 1] = 0;
                }
        }
}


int ReedSolomon::decode(std::vector<uint8_t>& data_to_decode, const std::vector<int>& erasure_positions) const
{
    int result = -1;
    if (erasure_positions.size() > std::size_t(d_nroots))
        {
            std::cerr << "Reed Solomon usage error: too much erasure positions.\n";
            return result;
        }
    size_t size_buffer = data_to_decode.size();
    if ((size_buffer != d_data_symbols_shortened) && (size_buffer != static_cast<size_t>(d_symbols_per_block)))
        {
            std::cerr << "Reed Solomon usage error: wrong vector input size in decode method.\n";
            return result;
        }

    if (d_shortening == 0 || (size_buffer == static_cast<size_t>(d_symbols_per_block)))
        {
            result = decode_rs_8(data_to_decode.data(), erasure_positions.data(), erasure_positions.size());
        }
    else
        {
            // Create unshortened code vector
            std::vector<uint8_t> unshortened_code_vector(d_symbols_per_block, 0);
            std::copy(data_to_decode.begin(), data_to_decode.begin() + d_info_symbols_shortened, unshortened_code_vector.begin());
            std::copy(data_to_decode.begin() + d_info_symbols_shortened, data_to_decode.begin() + d_data_symbols_shortened, unshortened_code_vector.begin() + d_data_in_block);

            result = decode_rs_8(unshortened_code_vector.data(), erasure_positions.data(), erasure_positions.size());
            if (result >= 0)
                {
                    // Store decoded result into the shortened code vector
                    std::copy(unshortened_code_vector.begin(), unshortened_code_vector.begin() + d_info_symbols_shortened, data_to_decode.begin());
                    std::copy(unshortened_code_vector.begin() + d_data_in_block, unshortened_code_vector.begin() + d_symbols_per_block, data_to_decode.begin() + d_info_symbols_shortened);
                }
        }
    return result;
}


int ReedSolomon::decode_rs_8(uint8_t* data, const int* eras_pos, int no_eras) const
{
    int deg_lambda;
    int el;
    int deg_omega;
    int i;
    int j;
    int r;
    int k;
    int syn_error;
    int count;

    uint8_t u;
    uint8_t q;
    uint8_t tmp;
    uint8_t num1;
    uint8_t num2;
    uint8_t den;
    uint8_t discr_r;

    std::vector<uint8_t> lambda(d_nroots + 1);  // Err+Eras Locator poly
    std::vector<uint8_t> s(d_nroots);           // syndrome poly
    std::vector<uint8_t> b(d_nroots + 1);
    std::vector<uint8_t> t(d_nroots + 1);
    std::vector<uint8_t> omega(d_nroots + 1);
    std::vector<uint8_t> root(d_nroots);
    std::vector<uint8_t> reg(d_nroots + 1);
    std::vector<uint8_t> loc(d_nroots);

    // Syndrome computation
    // form the syndromes; i.e., evaluate data(x) at roots of g(x)
    for (i = 0; i < d_nroots; i++)
        {
            s[i] = data[0];
        }

    for (j = 1; j < d_symbols_per_block - d_pad; j++)
        {
            for (i = 0; i < d_nroots; i++)
                {
                    if (s[i] == 0)
                        {
                            s[i] = data[j];
                        }
                    else
                        {
                            s[i] = data[j] ^ d_alpha_to[mod255(d_index_of[s[i]] + (d_fcr + i) * d_prim)];
                        }
                }
        }

    // Convert syndromes to index form, checking for nonzero condition
    syn_error = 0;
    for (i = 0; i < d_nroots; i++)
        {
            syn_error |= s[i];
            s[i] = d_index_of[s[i]];
        }

    if (!syn_error)
        {
            // if syndrome is zero, data[] is a codeword and there are no
            // errors to correct. So return data[] unmodified
            return 0;
        }

    lambda[0] = 1;

    if (no_eras > 0)
        {
            // Init lambda to be the erasure locator polynomial
            lambda[1] = d_alpha_to[mod255(d_prim * (d_symbols_per_block - 1 - eras_pos[0]))];
            for (i = 1; i < no_eras; i++)
                {
                    u = mod255(d_prim * (d_symbols_per_block - 1 - eras_pos[i]));
                    for (j = i + 1; j > 0; j--)
                        {
                            tmp = d_index_of[lambda[j - 1]];
                            if (tmp != d_a0)
                                {
                                    lambda[j] ^= d_alpha_to[mod255(u + tmp)];
                                }
                        }
                }
        }

    for (i = 0; i < d_nroots + 1; i++)
        {
            b[i] = d_index_of[lambda[i]];
        }

    // Begin Berlekamp-Massey algorithm to determine error+erasure
    // locator polynomial
    r = no_eras;
    el = no_eras;
    while (++r <= d_nroots)  // r is the step number
        {
            // Compute discrepancy at the r-th step in poly-form
            discr_r = 0;
            for (i = 0; i < r; i++)
                {
                    if ((lambda[i] != 0) && (s[r - i - 1] != d_a0))
                        {
                            discr_r ^= d_alpha_to[mod255(d_index_of[lambda[i]] + s[r - i - 1])];
                        }
                }
            discr_r = d_index_of[discr_r];  // Index form
            if (discr_r == d_a0)
                {
                    // line below: B(x) <-- x*B(x)
                    b.insert(b.begin(), d_a0);
                }
            else
                {
                    // 12 lines below: T(x) <-- lambda(x) - discr_r*x*b(x)
                    t[0] = lambda[0];
                    for (i = 0; i < d_nroots; i++)
                        {
                            if (b[i] != d_a0)
                                {
                                    t[i + 1] = lambda[i + 1] ^ d_alpha_to[mod255(discr_r + b[i])];
                                }
                            else
                                {
                                    t[i + 1] = lambda[i + 1];
                                }
                        }
                    if (2 * el <= r + no_eras - 1)
                        {
                            el = r + no_eras - el;
                            // 4 lines below: B(x) <-- inv(discr_r) * lambda(x)
                            for (i = 0; i <= d_nroots; i++)
                                {
                                    b[i] = (lambda[i] == 0) ? d_a0 : mod255(d_index_of[lambda[i]] - discr_r + d_symbols_per_block);
                                }
                        }
                    else
                        {
                            // line below: B(x) <-- x*B(x)
                            b.insert(b.begin(), d_a0);
                        }
                    memcpy(&lambda[0], t.data(), (d_nroots + 1) * sizeof(t[0]));
                }
        }

    // Convert lambda to index form and compute deg(lambda(x))
    deg_lambda = 0;
    for (i = 0; i < d_nroots + 1; i++)
        {
            lambda[i] = d_index_of[lambda[i]];
            if (lambda[i] != d_a0)
                {
                    deg_lambda = i;
                }
        }

    // Find roots of the error+erasure locator polynomial by Chien search
    memcpy(&reg[1], &lambda[1], d_nroots * sizeof(reg[0]));
    count = 0;  // Number of roots of lambda(x)
    for (i = 1, k = d_iprim - 1; i <= d_symbols_per_block; i++, k = mod255(k + d_iprim))
        {
            q = 1;  // lambda[0] is always 0
            for (j = deg_lambda; j > 0; j--)
                {
                    if (reg[j] != d_a0)
                        {
                            reg[j] = mod255(reg[j] + j);
                            q ^= d_alpha_to[reg[j]];
                        }
                }
            if (q != 0)
                {
                    // Not a root
                    // store root (index-form) and error location number
                    continue;
                }

            // Corrections of errors and erasures at the locations and magnitude
            // as per Chien Search and Forney Algorithm
            root[count] = i;
            loc[count] = k;
            // If we have already found max possible roots, abort the search to save time
            if (++count == deg_lambda)
                {
                    break;
                }
        }
    if (deg_lambda != count)
        {
            // deg(lambda) unequal to number of roots => uncorrectable
            // error detected
            return -1;
        }

    // Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
    // x**d_nroots). in index form. Also find deg(omega).
    deg_omega = deg_lambda - 1;
    for (i = 0; i <= deg_omega; i++)
        {
            tmp = 0;
            for (j = i; j >= 0; j--)
                {
                    if ((s[i - j] != d_a0) && (lambda[j] != d_a0))
                        {
                            tmp ^= d_alpha_to[mod255(s[i - j] + lambda[j])];
                        }
                }
            omega[i] = d_index_of[tmp];
        }

    // Compute error values in poly-form. num1 = omega(inv(X(l))),
    // num2 = inv(X(l))**(d_fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
    for (j = count - 1; j >= 0; j--)
        {
            num1 = 0;
            for (i = deg_omega; i >= 0; i--)
                {
                    if (omega[i] != d_a0)
                        {
                            num1 ^= d_alpha_to[mod255(omega[i] + i * root[j])];
                        }
                }
            num2 = d_alpha_to[mod255(root[j] * (d_fcr - 1) + d_symbols_per_block)];
            den = 0;

            // lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i]
            for (i = rs_min(deg_lambda, d_nroots - 1) & ~1; i >= 0; i -= 2)
                {
                    if (lambda[i + 1] != d_a0)
                        {
                            den ^= d_alpha_to[mod255(lambda[i + 1] + i * root[j])];
                        }
                }

            // Apply error to data
            if (num1 != 0 && loc[j] >= d_pad)
                {
                    data[loc[j] - d_pad] ^=
                        d_alpha_to[mod255(d_index_of[num1] + d_index_of[num2] + d_symbols_per_block - d_index_of[den])];
                }
        }

    return count;
}
